diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile deleted file mode 100644 index 8ea34be96..000000000 --- a/.devcontainer/Dockerfile +++ /dev/null @@ -1,23 +0,0 @@ -# syntax=docker/dockerfile:1 -FROM debian:bookworm-slim AS stainless - -RUN apt-get update && apt-get install -y \ - nodejs \ - npm \ - yarnpkg \ - && apt-get clean autoclean - -# Ensure UTF-8 encoding -ENV LANG=C.UTF-8 -ENV LC_ALL=C.UTF-8 - -# Yarn -RUN ln -sf /usr/bin/yarnpkg /usr/bin/yarn - -WORKDIR /workspace - -COPY package.json yarn.lock /workspace/ - -RUN yarn install - -COPY . /workspace diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index d55fc4d67..763462fad 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,20 +1,17 @@ // For format details, see https://aka.ms/devcontainer.json. For config options, see the // README at: https://github.com/devcontainers/templates/tree/main/src/debian { - "name": "Debian", - "build": { - "dockerfile": "Dockerfile" + "name": "Development", + "image": "mcr.microsoft.com/devcontainers/typescript-node:latest", + "features": { + "ghcr.io/devcontainers/features/node:1": {} + }, + "postCreateCommand": "yarn install", + "customizations": { + "vscode": { + "extensions": [ + "esbenp.prettier-vscode" + ] + } } - - // Features to add to the dev container. More info: https://containers.dev/features. - // "features": {}, - - // Use 'forwardPorts' to make a list of ports inside the container available locally. - // "forwardPorts": [], - - // Configure tool-specific properties. - // "customizations": {}, - - // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. - // "remoteUser": "root" } diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index 60f0e7a35..000000000 --- a/.eslintrc.js +++ /dev/null @@ -1,10 +0,0 @@ -module.exports = { - parser: '@typescript-eslint/parser', - plugins: ['@typescript-eslint', 'unused-imports', 'prettier'], - rules: { - 'no-unused-vars': 'off', - 'prettier/prettier': 'error', - 'unused-imports/no-unused-imports': 'error', - }, - root: true, -}; diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d6798e38a..449c4778f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,6 +7,7 @@ on: branches: - master - next + - alpha jobs: lint: @@ -64,3 +65,36 @@ jobs: - name: Run tests run: ./scripts/test + + ecosystem_tests: + name: ecosystem tests (v${{ matrix.node-version }}) + runs-on: ubuntu-latest + if: github.repository == 'openai/openai-node' + timeout-minutes: 20 + strategy: + fail-fast: false + matrix: + node-version: ['18', '20'] + + steps: + - uses: actions/checkout@v4 + + - name: Set up Node + uses: actions/setup-node@v4 + with: + node-version: '${{ matrix.node-version }}' + + - uses: denoland/setup-deno@v1 + with: + deno-version: v1.39.0 + + - uses: oven-sh/setup-bun@v2 + + - name: Bootstrap + run: ./scripts/bootstrap + + - name: Run ecosystem tests + run: | + yarn tsn ecosystem-tests/cli.ts --live --verbose --parallel --jobs=4 --retry=3 + env: + OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 6b843f931..721222a67 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "4.77.0" + ".": "5.0.0-beta.0" } diff --git a/.stats.yml b/.stats.yml index 7b5235e3c..163146e38 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,2 +1,2 @@ -configured_endpoints: 68 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-0d64ca9e45f51b4279f87b205eeb3a3576df98407698ce053f2e2302c1c08df1.yml +configured_endpoints: 74 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai-5d30684c3118d049682ea30cdb4dbef39b97d51667da484689193dc40162af32.yml diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e8bbc1b07..dde09d52d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,6 +1,6 @@ ## Setting up the environment -This repository uses [`yarn@v1`](https://classic.yarnpkg.com/lang/en/docs/install/#mac-stable). +This repository uses [`yarn@v1`](https://classic.yarnpkg.com/lang/en/docs/install). Other package managers may work but are not officially supported for development. To set up the repository, run: @@ -29,10 +29,10 @@ All files in the `examples/` directory are not modified by the generator and can … ``` -``` -chmod +x examples/.ts +```sh +$ chmod +x examples/.ts # run the example against your api -yarn tsn -T examples/.ts +$ yarn tsn -T examples/.ts ``` ## Using the repository from source diff --git a/LICENSE b/LICENSE index 621a6becf..f011417af 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2024 OpenAI + Copyright 2025 OpenAI Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/MIGRATION.md b/MIGRATION.md new file mode 100644 index 000000000..c9c07887c --- /dev/null +++ b/MIGRATION.md @@ -0,0 +1,380 @@ +# Migration guide + +This guide outlines the changes and steps needed to migrate your codebase to the latest version of the OpenAI TypeScript and JavaScript SDK. + +The main changes are that the SDK now relies on the [builtin Web fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) instead of `node-fetch` and has zero dependencies. + +## Environment requirements + +The minimum supported runtime and tooling versions are now: + +- Node.js 18.x last LTS (Required for built-in fetch support) + - This was previously documented as the minimum supported Node.js version but Node.js 16.x mostly worked at runtime; now it will not. +- TypeScript 4.9 +- Jest 28 + +## Minimum types requirements + +### DOM + +`tsconfig.json` + +```jsonc +{ + "target": "ES2015", // note: we recommend ES2020 or higher + "lib": ["DOM", "DOM.Iterable", "ES2018"] +} +``` + +### Node.js + +`tsconfig.json` + +```jsonc +{ + "target": "ES2015" // note: we recommend ES2020 or higher +} +``` + +`package.json` + +```json +{ + "devDependencies": { + "@types/node": ">= 18.18.7" + } +} +``` + +### Cloudflare Workers + +`tsconfig.json` + +```jsonc +{ + "target": "ES2015", // note: we recommend ES2020 or higher + "lib": ["ES2020"], // <- needed by @cloudflare/workers-types + "types": ["@cloudflare/workers-types"] +} +``` + +`package.json` + +```json +{ + "devDependencies": { + "@cloudflare/workers-types": ">= 0.20221111.0" + } +} +``` + +### Bun + +`tsconfig.json` + +```jsonc +{ + "target": "ES2015" // note: we recommend ES2020 or higher +} +``` + +`package.json` + +```json +{ + "devDependencies": { + "@types/bun": ">= 1.2.0" + } +} +``` + +### Deno + +No config needed! + +## Breaking changes + +### Named path parameters + +Methods that take multiple path parameters typically now use named instead of positional arguments for better clarity and to prevent a footgun where it was easy to accidentally pass arguments in the incorrect order. + +For example, for a method that would call an endpoint at `/v1/parents/{parent_id}/children/{child_id}`, only the _last_ path parameter is positional and the rest must be passed as named arguments. + +```ts +// Before +client.parents.children.create('p_123', 'c_456'); + +// After +client.example.create('c_456', { parent_id: 'p_123' }); +``` + +This affects the following methods: + +- `client.beta.vectorStores.files.retrieve()` +- `client.beta.vectorStores.files.delete()` +- `client.beta.vectorStores.fileBatches.retrieve()` +- `client.beta.vectorStores.fileBatches.cancel()` +- `client.beta.vectorStores.fileBatches.listFiles()` +- `client.beta.threads.runs.retrieve()` +- `client.beta.threads.runs.update()` +- `client.beta.threads.runs.cancel()` +- `client.beta.threads.runs.submitToolOutputs()` +- `client.beta.threads.runs.steps.retrieve()` +- `client.beta.threads.runs.steps.list()` +- `client.beta.threads.messages.retrieve()` +- `client.beta.threads.messages.update()` +- `client.beta.threads.messages.delete()` + +### URI encoded path parameters + +Path params are now properly encoded by default. If you were manually encoding path parameters before giving them to the SDK, you must now stop doing that and pass the +param without any encoding applied. + +For example: + +```diff +- client.example.retrieve(encodeURIComponent('string/with/slash')) ++ client.example.retrieve('string/with/slash') // renders example/string%2Fwith%2Fslash +``` + +Previously without the `encodeURIComponent()` call we would have used the path `/example/string/with/slash`; now we'll use `/example/string%2Fwith%2Fslash`. + +### Removed `httpAgent` in favor of `fetchOptions` + +The `httpAgent` client option has been removed in favor of a [platform-specific `fetchOptions` property](https://github.com/stainless-sdks/openai-typescript#fetch-options). +This change was made as `httpAgent` relied on `node:http` agents which are not supported by any runtime's builtin fetch implementation. + +If you were using `httpAgent` for proxy support, check out the [new proxy documentation](https://github.com/stainless-sdks/openai-typescript#configuring-proxies). + +Before: + +```ts +import OpenAI from 'openai'; +import http from 'http'; +import { HttpsProxyAgent } from 'https-proxy-agent'; + +// Configure the default for all requests: +const client = new OpenAI({ + httpAgent: new HttpsProxyAgent(process.env.PROXY_URL), +}); +``` + +After: + +```ts +import OpenAI from 'openai'; +import * as undici from 'undici'; + +const proxyAgent = new undici.ProxyAgent(process.env.PROXY_URL); +const client = new OpenAI({ + fetchOptions: { + dispatcher: proxyAgent, + }, +}); +``` + +### HTTP method naming + +Some methods could not be named intuitively due to an internal naming conflict. This has been resolved and the methods are now correctly named. + +```ts +// Before +client.chat.completions.del(); +client.files.del(); +client.models.del(); +client.beta.vectorStores.del(); +client.beta.vectorStores.files.del(); +client.beta.assistants.del(); +client.beta.threads.del(); +client.beta.threads.messages.del(); + +// After +client.chat.completions.delete(); +client.files.delete(); +client.models.delete(); +client.beta.vectorStores.delete(); +client.beta.vectorStores.files.delete(); +client.beta.assistants.delete(); +client.beta.threads.delete(); +client.beta.threads.messages.delete(); +``` + +### Removed request options overloads + +When making requests with no required body, query or header parameters, you must now explicitly pass `null`, `undefined` or an empty object `{}` to the params argument in order to customise request options. + +```diff +client.example.list(); +client.example.list({}, { headers: { ... } }); +client.example.list(null, { headers: { ... } }); +client.example.list(undefined, { headers: { ... } }); +- client.example.list({ headers: { ... } }); ++ client.example.list({}, { headers: { ... } }); +``` + +This affects the following methods: + +- `client.chat.completions.list()` +- `client.chat.completions.messages.list()` +- `client.files.list()` +- `client.fineTuning.jobs.list()` +- `client.fineTuning.jobs.listEvents()` +- `client.fineTuning.jobs.checkpoints.list()` +- `client.beta.vectorStores.list()` +- `client.beta.vectorStores.files.list()` +- `client.beta.assistants.list()` +- `client.beta.threads.create()` +- `client.beta.threads.runs.list()` +- `client.beta.threads.messages.list()` +- `client.batches.list()` + +### Pagination changes + +Note that the `for await` syntax is _not_ affected. This still works as-is: + +```ts +// Automatically fetches more pages as needed. +for await (const fineTuningJob of client.fineTuning.jobs.list()) { + console.log(fineTuningJob); +} +``` + +#### Simplified interface + +The pagination interface has been simplified: + +```ts +// Before +page.nextPageParams(); +page.nextPageInfo(); +// Required manually handling { url } | { params } type + +// After +page.nextPageRequestOptions(); +``` + +#### Removed unnecessary classes + +Page classes for individual methods are now type aliases: + +```ts +// Before +export class FineTuningJobsPage extends CursorPage {} + +// After +export type FineTuningJobsPage = CursorPage; +``` + +If you were importing these classes at runtime, you'll need to switch to importing the base class or only import them at the type-level. + +### File handling + +The deprecated `fileFromPath` helper has been removed in favor of native Node.js streams: + +```ts +// Before +OpenAI.fileFromPath('path/to/file'); + +// After +import fs from 'fs'; +fs.createReadStream('path/to/file'); +``` + +Note that this function previously only worked on Node.j. If you're using Bun, you can use [`Bun.file`](https://bun.sh/docs/api/file-io) instead. + +### Shims removal + +Previously you could configure the types that the SDK used like this: + +```ts +// Tell TypeScript and the package to use the global Web fetch instead of node-fetch. +import 'openai/shims/web'; +import OpenAI from 'openai'; +``` + +The `openai/shims` imports have been removed. Your global types must now be [correctly configured](#minimum-types-requirements). + +### `openai/src` directory removed + +Previously IDEs may have auto-completed imports from the `openai/src` directory, however this +directory was only included for an improved go-to-definition experience and should not have been used at runtime. + +If you have any `openai/src` imports, you must replace it with `openai`. + +```ts +// Before +import OpenAI from 'openai/src'; + +// After +import OpenAI from 'openai'; +``` + +### Headers + +The `headers` property on `APIError` objects is now an instance of the Web [Headers](https://developer.mozilla.org/en-US/docs/Web/API/Headers) class. It was previously just `Record`. + +### Removed exports + +#### `Response` + +```typescript +// Before +import { Response } from 'openai'; + +// After +// `Response` must now come from the builtin types +``` + +#### Resource classes + +If you were importing resource classes from the root package then you must now import them from the file they are defined in: + +```typescript +// Before +import { Completions } from 'openai'; + +// After +import { Completions } from 'openai/resources/completions'; +``` + +#### `openai/core` + +The `openai/core` file was intended to be internal-only but it was publicly accessible, as such it has been refactored and split up into internal files. + +If you were relying on anything that was only exported from `openai/core` and is also not accessible anywhere else, please open an issue and we'll consider adding it to the public API. + +#### `APIClient` + +The `APIClient` base client class has been removed as it is no longer needed. If you were importing this class then you must now import the main client class: + +```typescript +// Before +import { APIClient } from 'openai/core'; + +// After +import { OpenAI } from 'openai'; +``` + +#### Cleaned up `openai/uploads` exports + +The following exports have been removed from `openai/uploads` as they were not intended to be a part of the public API: + +- `fileFromPath` +- `BlobPart` +- `BlobLike` +- `FileLike` +- `ResponseLike` +- `isResponseLike` +- `isBlobLike` +- `isFileLike` +- `isUploadable` +- `isMultipartBody` +- `maybeMultipartFormRequestOptions` +- `multipartFormRequestOptions` +- `createForm` + +Note that `Uploadable` & `toFile` **are** still exported: + +```typescript +import { type Uploadable, toFile } from 'openai/uploads'; +``` diff --git a/README.md b/README.md index b03bcd870..08226e928 100644 --- a/README.md +++ b/README.md @@ -287,8 +287,6 @@ main(); Like with `.stream()`, we provide a variety of [helpers and events](helpers.md#chat-events). -Note that `runFunctions` was previously available as well, but has been deprecated in favor of `runTools`. - Read more about various examples such as with integrating with [zod](helpers.md#integrate-with-zod), [next.js](helpers.md#integrate-with-nextjs), and [proxying a stream to the browser](helpers.md#proxy-streaming-to-a-browser). @@ -303,7 +301,6 @@ Request parameters that correspond to file uploads can be passed in many differe ```ts import fs from 'fs'; -import fetch from 'node-fetch'; import OpenAI, { toFile } from 'openai'; const client = new OpenAI(); @@ -389,6 +386,20 @@ const { data: stream, request_id } = await openai.chat.completions .withResponse(); ``` +## Realtime API Beta + +The Realtime API enables you to build low-latency, multi-modal conversational experiences. It currently supports text and audio as both input and output, as well as [function calling](https://platform.openai.com/docs/guides/function-calling) through a `WebSocket` connection. + +```ts +import { OpenAIRealtimeWebSocket } from 'openai/beta/realtime/websocket'; + +const rt = new OpenAIRealtimeWebSocket({ model: 'gpt-4o-realtime-preview-2024-12-17' }); + +rt.on('response.text.delta', (event) => process.stdout.write(event.delta)); +``` + +For more information see [realtime.md](realtime.md). + ## Microsoft Azure OpenAI To use this library with [Azure OpenAI](https://learn.microsoft.com/azure/ai-services/openai/overview), use the `AzureOpenAI` @@ -514,6 +525,59 @@ console.log(raw.headers.get('X-My-Header')); console.log(chatCompletion); ``` +### Logging + +> [!IMPORTANT] +> All log messages are intended for debugging only. The format and content of log messages +> may change between releases. + +#### Log levels + +The log level can be configured in two ways: + +1. Via the `OPENAI_LOG` environment variable +2. Using the `logLevel` client option (overrides the environment variable if set) + +```ts +import OpenAI from 'openai'; + +const client = new OpenAI({ + logLevel: 'debug', // Show all log messages +}); +``` + +Available log levels, from most to least verbose: + +- `'debug'` - Show debug messages, info, warnings, and errors +- `'info'` - Show info messages, warnings, and errors +- `'warn'` - Show warnings and errors (default) +- `'error'` - Show only errors +- `'off'` - Disable all logging + +At the `'debug'` level, all HTTP requests and responses are logged, including headers and bodies. +Some authentication-related headers are redacted, but sensitive data in request and response bodies +may still be visible. + +#### Custom logger + +By default, this library logs to `globalThis.console`. You can also provide a custom logger. +Most logging libraries are supported, including [pino](https://www.npmjs.com/package/pino), [winston](https://www.npmjs.com/package/winston), [bunyan](https://www.npmjs.com/package/bunyan), [consola](https://www.npmjs.com/package/consola), [signale](https://www.npmjs.com/package/signale), and [@std/log](https://jsr.io/@std/log). If your logger doesn't work, please open an issue. + +When providing a custom logger, the `logLevel` option still controls which messages are emitted, messages +below the configured level will not be sent to your logger. + +```ts +import OpenAI from 'openai'; +import pino from 'pino'; + +const logger = pino(); + +const client = new OpenAI({ + logger: logger.child({ name: 'OpenAI' }), + logLevel: 'debug', // Send all messages to pino, allowing it to filter +}); +``` + ### Making custom/undocumented requests This library is typed for convenient access to the documented API. If you need to access undocumented @@ -560,72 +624,91 @@ validate or strip extra properties from the response from the API. ### Customizing the fetch client -By default, this library uses `node-fetch` in Node, and expects a global `fetch` function in other environments. +By default, this library expects a global `fetch` function is defined. -If you would prefer to use a global, web-standards-compliant `fetch` function even in a Node environment, -(for example, if you are running Node with `--experimental-fetch` or using NextJS which polyfills with `undici`), -add the following import before your first import `from "OpenAI"`: +If you want to use a different `fetch` function, you can either polyfill the global: ```ts -// Tell TypeScript and the package to use the global web fetch instead of node-fetch. -// Note, despite the name, this does not add any polyfills, but expects them to be provided if needed. -import 'openai/shims/web'; -import OpenAI from 'openai'; +import fetch from 'my-fetch'; + +globalThis.fetch = fetch; ``` -To do the inverse, add `import "openai/shims/node"` (which does import polyfills). -This can also be useful if you are getting the wrong TypeScript types for `Response` ([more details](https://github.com/openai/openai-node/tree/master/src/_shims#readme)). +Or pass it to the client: + +```ts +import OpenAI from 'openai'; +import fetch from 'my-fetch'; + +const client = new OpenAI({ fetch }); +``` -### Logging and middleware +### Fetch options -You may also provide a custom `fetch` function when instantiating the client, -which can be used to inspect or alter the `Request` or `Response` before/after each request: +If you want to set custom `fetch` options without overriding the `fetch` function, you can provide a `fetchOptions` object when instantiating the client or making a request. (Request-specific options override client options.) ```ts -import { fetch } from 'undici'; // as one example import OpenAI from 'openai'; const client = new OpenAI({ - fetch: async (url: RequestInfo, init?: RequestInit): Promise => { - console.log('About to make a request', url, init); - const response = await fetch(url, init); - console.log('Got response', response); - return response; + fetchOptions: { + // `RequestInit` options }, }); ``` -Note that if given a `DEBUG=true` environment variable, this library will log all requests and responses automatically. -This is intended for debugging purposes only and may change in the future without notice. +#### Configuring proxies -### Configuring an HTTP(S) Agent (e.g., for proxies) +To modify proxy behavior, you can provide custom `fetchOptions` that add runtime-specific proxy +options to requests: -By default, this library uses a stable agent for all http/https requests to reuse TCP connections, eliminating many TCP & TLS handshakes and shaving around 100ms off most requests. + **Node** [[docs](https://github.com/nodejs/undici/blob/main/docs/docs/api/ProxyAgent.md#example---proxyagent-with-fetch)] -If you would like to disable or customize this behavior, for example to use the API behind a proxy, you can pass an `httpAgent` which is used for all requests (be they http or https), for example: +```ts +import OpenAI from 'openai'; +import * as undici from 'undici'; + +const proxyAgent = new undici.ProxyAgent('http://localhost:8888/'); +const client = new OpenAI({ + fetchOptions: { + dispatcher: proxyAgent, + }, +}); +``` + + **Bun** [[docs](https://bun.sh/guides/http/proxy)] - ```ts -import http from 'http'; -import { HttpsProxyAgent } from 'https-proxy-agent'; +import OpenAI from 'openai'; -// Configure the default for all requests: const client = new OpenAI({ - httpAgent: new HttpsProxyAgent(process.env.PROXY_URL), + fetchOptions: { + proxy: 'http://localhost:8888/', + }, }); +``` -// Override per-request: -await client.models.list({ - httpAgent: new http.Agent({ keepAlive: false }), + **Deno** [[docs](https://docs.deno.com/api/deno/~/Deno.createHttpClient)] + +```ts +import OpenAI from 'npm:openai'; + +const httpClient = Deno.createHttpClient({ proxy: { url: 'http://localhost:8888/' } }); +const client = new OpenAI({ + fetchOptions: { + client: httpClient, + }, }); ``` +## Frequently Asked Questions + ## Semantic versioning This package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions: 1. Changes that only affect static types, without breaking runtime behavior. -2. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals)_. +2. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals.)_ 3. Changes that we do not expect to impact the vast majority of users in practice. We take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience. @@ -634,7 +717,7 @@ We are keen for your feedback; please open an [issue](https://www.github.com/ope ## Requirements -TypeScript >= 4.5 is supported. +TypeScript >= 4.9 is supported. The following runtimes are supported: diff --git a/SECURITY.md b/SECURITY.md index c54acaf33..3b3bd8a66 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -2,9 +2,9 @@ ## Reporting Security Issues -This SDK is generated by [Stainless Software Inc](http://stainlessapi.com). Stainless takes security seriously, and encourages you to report any security vulnerability promptly so that appropriate action can be taken. +This SDK is generated by [Stainless Software Inc](http://stainless.com). Stainless takes security seriously, and encourages you to report any security vulnerability promptly so that appropriate action can be taken. -To report a security issue, please contact the Stainless team at security@stainlessapi.com. +To report a security issue, please contact the Stainless team at security@stainless.com. ## Responsible Disclosure diff --git a/api.md b/api.md index 54bcf08d7..978bff992 100644 --- a/api.md +++ b/api.md @@ -5,6 +5,7 @@ Types: - ErrorObject - FunctionDefinition - FunctionParameters +- Metadata - ResponseFormatJSONObject - ResponseFormatJSONSchema - ResponseFormatText @@ -31,39 +32,50 @@ Types: Types: -- ChatCompletion -- ChatCompletionAssistantMessageParam -- ChatCompletionAudio -- ChatCompletionAudioParam -- ChatCompletionChunk -- ChatCompletionContentPart -- ChatCompletionContentPartImage -- ChatCompletionContentPartInputAudio -- ChatCompletionContentPartRefusal -- ChatCompletionContentPartText -- ChatCompletionDeveloperMessageParam -- ChatCompletionFunctionCallOption -- ChatCompletionFunctionMessageParam -- ChatCompletionMessage -- ChatCompletionMessageParam -- ChatCompletionMessageToolCall -- ChatCompletionModality -- ChatCompletionNamedToolChoice -- ChatCompletionPredictionContent -- ChatCompletionReasoningEffort -- ChatCompletionRole -- ChatCompletionStreamOptions -- ChatCompletionSystemMessageParam -- ChatCompletionTokenLogprob -- ChatCompletionTool -- ChatCompletionToolChoiceOption -- ChatCompletionToolMessageParam -- ChatCompletionUserMessageParam -- CreateChatCompletionRequestMessage +- ChatCompletion +- ChatCompletionAssistantMessageParam +- ChatCompletionAudio +- ChatCompletionAudioParam +- ChatCompletionChunk +- ChatCompletionContentPart +- ChatCompletionContentPartImage +- ChatCompletionContentPartInputAudio +- ChatCompletionContentPartRefusal +- ChatCompletionContentPartText +- ChatCompletionDeleted +- ChatCompletionDeveloperMessageParam +- ChatCompletionFunctionCallOption +- ChatCompletionFunctionMessageParam +- ChatCompletionMessage +- ChatCompletionMessageParam +- ChatCompletionMessageToolCall +- ChatCompletionModality +- ChatCompletionNamedToolChoice +- ChatCompletionPredictionContent +- ChatCompletionReasoningEffort +- ChatCompletionRole +- ChatCompletionStoreMessage +- ChatCompletionStreamOptions +- ChatCompletionSystemMessageParam +- ChatCompletionTokenLogprob +- ChatCompletionTool +- ChatCompletionToolChoiceOption +- ChatCompletionToolMessageParam +- ChatCompletionUserMessageParam Methods: -- client.chat.completions.create({ ...params }) -> ChatCompletion +- client.chat.completions.create({ ...params }) -> ChatCompletion +- client.chat.completions.retrieve(completionID) -> ChatCompletion +- client.chat.completions.update(completionID, { ...params }) -> ChatCompletion +- client.chat.completions.list({ ...params }) -> ChatCompletionsPage +- client.chat.completions.delete(completionID) -> ChatCompletionDeleted + +### Messages + +Methods: + +- client.chat.completions.messages.list(completionID, { ...params }) -> ChatCompletionStoreMessagesPage # Embeddings @@ -89,11 +101,10 @@ Types: Methods: - client.files.create({ ...params }) -> FileObject -- client.files.retrieve(fileId) -> FileObject +- client.files.retrieve(fileID) -> FileObject - client.files.list({ ...params }) -> FileObjectsPage -- client.files.del(fileId) -> FileDeleted -- client.files.content(fileId) -> Response -- client.files.retrieveContent(fileId) -> string +- client.files.delete(fileID) -> FileDeleted +- client.files.content(fileID) -> Response - client.files.waitForProcessing(id, { pollInterval = 5000, maxWait = 30 _ 60 _ 1000 }) -> Promise<FileObject> # Images @@ -179,7 +190,7 @@ Methods: - client.models.retrieve(model) -> Model - client.models.list() -> ModelsPage -- client.models.del(model) -> ModelDeleted +- client.models.delete(model) -> ModelDeleted # FineTuning @@ -196,10 +207,10 @@ Types: Methods: - client.fineTuning.jobs.create({ ...params }) -> FineTuningJob -- client.fineTuning.jobs.retrieve(fineTuningJobId) -> FineTuningJob +- client.fineTuning.jobs.retrieve(fineTuningJobID) -> FineTuningJob - client.fineTuning.jobs.list({ ...params }) -> FineTuningJobsPage -- client.fineTuning.jobs.cancel(fineTuningJobId) -> FineTuningJob -- client.fineTuning.jobs.listEvents(fineTuningJobId, { ...params }) -> FineTuningJobEventsPage +- client.fineTuning.jobs.cancel(fineTuningJobID) -> FineTuningJob +- client.fineTuning.jobs.listEvents(fineTuningJobID, { ...params }) -> FineTuningJobEventsPage ### Checkpoints @@ -209,10 +220,71 @@ Types: Methods: -- client.fineTuning.jobs.checkpoints.list(fineTuningJobId, { ...params }) -> FineTuningJobCheckpointsPage +- client.fineTuning.jobs.checkpoints.list(fineTuningJobID, { ...params }) -> FineTuningJobCheckpointsPage # Beta +## Realtime + +Types: + +- ConversationCreatedEvent +- ConversationItem +- ConversationItemContent +- ConversationItemCreateEvent +- ConversationItemCreatedEvent +- ConversationItemDeleteEvent +- ConversationItemDeletedEvent +- ConversationItemInputAudioTranscriptionCompletedEvent +- ConversationItemInputAudioTranscriptionFailedEvent +- ConversationItemTruncateEvent +- ConversationItemTruncatedEvent +- ConversationItemWithReference +- ErrorEvent +- InputAudioBufferAppendEvent +- InputAudioBufferClearEvent +- InputAudioBufferClearedEvent +- InputAudioBufferCommitEvent +- InputAudioBufferCommittedEvent +- InputAudioBufferSpeechStartedEvent +- InputAudioBufferSpeechStoppedEvent +- RateLimitsUpdatedEvent +- RealtimeClientEvent +- RealtimeResponse +- RealtimeResponseStatus +- RealtimeResponseUsage +- RealtimeServerEvent +- ResponseAudioDeltaEvent +- ResponseAudioDoneEvent +- ResponseAudioTranscriptDeltaEvent +- ResponseAudioTranscriptDoneEvent +- ResponseCancelEvent +- ResponseContentPartAddedEvent +- ResponseContentPartDoneEvent +- ResponseCreateEvent +- ResponseCreatedEvent +- ResponseDoneEvent +- ResponseFunctionCallArgumentsDeltaEvent +- ResponseFunctionCallArgumentsDoneEvent +- ResponseOutputItemAddedEvent +- ResponseOutputItemDoneEvent +- ResponseTextDeltaEvent +- ResponseTextDoneEvent +- SessionCreatedEvent +- SessionUpdateEvent +- SessionUpdatedEvent + +### Sessions + +Types: + +- Session +- SessionCreateResponse + +Methods: + +- client.beta.realtime.sessions.create({ ...params }) -> SessionCreateResponse + ## VectorStores Types: @@ -223,17 +295,17 @@ Types: - OtherFileChunkingStrategyObject - StaticFileChunkingStrategy - StaticFileChunkingStrategyObject -- StaticFileChunkingStrategyParam +- StaticFileChunkingStrategyObjectParam - VectorStore - VectorStoreDeleted Methods: - client.beta.vectorStores.create({ ...params }) -> VectorStore -- client.beta.vectorStores.retrieve(vectorStoreId) -> VectorStore -- client.beta.vectorStores.update(vectorStoreId, { ...params }) -> VectorStore +- client.beta.vectorStores.retrieve(vectorStoreID) -> VectorStore +- client.beta.vectorStores.update(vectorStoreID, { ...params }) -> VectorStore - client.beta.vectorStores.list({ ...params }) -> VectorStoresPage -- client.beta.vectorStores.del(vectorStoreId) -> VectorStoreDeleted +- client.beta.vectorStores.delete(vectorStoreID) -> VectorStoreDeleted ### Files @@ -244,10 +316,10 @@ Types: Methods: -- client.beta.vectorStores.files.create(vectorStoreId, { ...params }) -> VectorStoreFile -- client.beta.vectorStores.files.retrieve(vectorStoreId, fileId) -> VectorStoreFile -- client.beta.vectorStores.files.list(vectorStoreId, { ...params }) -> VectorStoreFilesPage -- client.beta.vectorStores.files.del(vectorStoreId, fileId) -> VectorStoreFileDeleted +- client.beta.vectorStores.files.create(vectorStoreID, { ...params }) -> VectorStoreFile +- client.beta.vectorStores.files.retrieve(fileID, { ...params }) -> VectorStoreFile +- client.beta.vectorStores.files.list(vectorStoreID, { ...params }) -> VectorStoreFilesPage +- client.beta.vectorStores.files.delete(fileID, { ...params }) -> VectorStoreFileDeleted - client.beta.vectorStores.files.createAndPoll(vectorStoreId, body, options?) -> Promise<VectorStoreFile> - client.beta.vectorStores.files.poll(vectorStoreId, fileId, options?) -> Promise<VectorStoreFile> - client.beta.vectorStores.files.upload(vectorStoreId, file, options?) -> Promise<VectorStoreFile> @@ -261,10 +333,10 @@ Types: Methods: -- client.beta.vectorStores.fileBatches.create(vectorStoreId, { ...params }) -> VectorStoreFileBatch -- client.beta.vectorStores.fileBatches.retrieve(vectorStoreId, batchId) -> VectorStoreFileBatch -- client.beta.vectorStores.fileBatches.cancel(vectorStoreId, batchId) -> VectorStoreFileBatch -- client.beta.vectorStores.fileBatches.listFiles(vectorStoreId, batchId, { ...params }) -> VectorStoreFilesPage +- client.beta.vectorStores.fileBatches.create(vectorStoreID, { ...params }) -> VectorStoreFileBatch +- client.beta.vectorStores.fileBatches.retrieve(batchID, { ...params }) -> VectorStoreFileBatch +- client.beta.vectorStores.fileBatches.cancel(batchID, { ...params }) -> VectorStoreFileBatch +- client.beta.vectorStores.fileBatches.listFiles(batchID, { ...params }) -> VectorStoreFilesPage - client.beta.vectorStores.fileBatches.createAndPoll(vectorStoreId, body, options?) -> Promise<VectorStoreFileBatch> - client.beta.vectorStores.fileBatches.poll(vectorStoreId, batchId, options?) -> Promise<VectorStoreFileBatch> - client.beta.vectorStores.fileBatches.uploadAndPoll(vectorStoreId, { files, fileIds = [] }, options?) -> Promise<VectorStoreFileBatch> @@ -275,7 +347,6 @@ Methods: Methods: -- client.beta.chat.completions.runFunctions(body, options?) -> ChatCompletionRunner | ChatCompletionStreamingRunner - client.beta.chat.completions.runTools(body, options?) -> ChatCompletionRunner | ChatCompletionStreamingRunner - client.beta.chat.completions.stream(body, options?) -> ChatCompletionStream @@ -298,10 +369,10 @@ Types: Methods: - client.beta.assistants.create({ ...params }) -> Assistant -- client.beta.assistants.retrieve(assistantId) -> Assistant -- client.beta.assistants.update(assistantId, { ...params }) -> Assistant +- client.beta.assistants.retrieve(assistantID) -> Assistant +- client.beta.assistants.update(assistantID, { ...params }) -> Assistant - client.beta.assistants.list({ ...params }) -> AssistantsPage -- client.beta.assistants.del(assistantId) -> AssistantDeleted +- client.beta.assistants.delete(assistantID) -> AssistantDeleted ## Threads @@ -317,9 +388,9 @@ Types: Methods: - client.beta.threads.create({ ...params }) -> Thread -- client.beta.threads.retrieve(threadId) -> Thread -- client.beta.threads.update(threadId, { ...params }) -> Thread -- client.beta.threads.del(threadId) -> ThreadDeleted +- client.beta.threads.retrieve(threadID) -> Thread +- client.beta.threads.update(threadID, { ...params }) -> Thread +- client.beta.threads.delete(threadID) -> ThreadDeleted - client.beta.threads.createAndRun({ ...params }) -> Run - client.beta.threads.createAndRunPoll(body, options?) -> Promise<Threads.Run> - client.beta.threads.createAndRunStream(body, options?) -> AssistantStream @@ -334,12 +405,12 @@ Types: Methods: -- client.beta.threads.runs.create(threadId, { ...params }) -> Run -- client.beta.threads.runs.retrieve(threadId, runId) -> Run -- client.beta.threads.runs.update(threadId, runId, { ...params }) -> Run -- client.beta.threads.runs.list(threadId, { ...params }) -> RunsPage -- client.beta.threads.runs.cancel(threadId, runId) -> Run -- client.beta.threads.runs.submitToolOutputs(threadId, runId, { ...params }) -> Run +- client.beta.threads.runs.create(threadID, { ...params }) -> Run +- client.beta.threads.runs.retrieve(runID, { ...params }) -> Run +- client.beta.threads.runs.update(runID, { ...params }) -> Run +- client.beta.threads.runs.list(threadID, { ...params }) -> RunsPage +- client.beta.threads.runs.cancel(runID, { ...params }) -> Run +- client.beta.threads.runs.submitToolOutputs(runID, { ...params }) -> Run - client.beta.threads.runs.createAndPoll(threadId, body, options?) -> Promise<Run> - client.beta.threads.runs.createAndStream(threadId, body, options?) -> AssistantStream - client.beta.threads.runs.poll(threadId, runId, options?) -> Promise<Run> @@ -372,8 +443,8 @@ Types: Methods: -- client.beta.threads.runs.steps.retrieve(threadId, runId, stepId, { ...params }) -> RunStep -- client.beta.threads.runs.steps.list(threadId, runId, { ...params }) -> RunStepsPage +- client.beta.threads.runs.steps.retrieve(stepID, { ...params }) -> RunStep +- client.beta.threads.runs.steps.list(runID, { ...params }) -> RunStepsPage ### Messages @@ -410,11 +481,11 @@ Types: Methods: -- client.beta.threads.messages.create(threadId, { ...params }) -> Message -- client.beta.threads.messages.retrieve(threadId, messageId) -> Message -- client.beta.threads.messages.update(threadId, messageId, { ...params }) -> Message -- client.beta.threads.messages.list(threadId, { ...params }) -> MessagesPage -- client.beta.threads.messages.del(threadId, messageId) -> MessageDeleted +- client.beta.threads.messages.create(threadID, { ...params }) -> Message +- client.beta.threads.messages.retrieve(messageID, { ...params }) -> Message +- client.beta.threads.messages.update(messageID, { ...params }) -> Message +- client.beta.threads.messages.list(threadID, { ...params }) -> MessagesPage +- client.beta.threads.messages.delete(messageID, { ...params }) -> MessageDeleted # Batches @@ -427,9 +498,9 @@ Types: Methods: - client.batches.create({ ...params }) -> Batch -- client.batches.retrieve(batchId) -> Batch +- client.batches.retrieve(batchID) -> Batch - client.batches.list({ ...params }) -> BatchesPage -- client.batches.cancel(batchId) -> Batch +- client.batches.cancel(batchID) -> Batch # Uploads @@ -440,8 +511,8 @@ Types: Methods: - client.uploads.create({ ...params }) -> Upload -- client.uploads.cancel(uploadId) -> Upload -- client.uploads.complete(uploadId, { ...params }) -> Upload +- client.uploads.cancel(uploadID) -> Upload +- client.uploads.complete(uploadID, { ...params }) -> Upload ## Parts @@ -451,4 +522,4 @@ Types: Methods: -- client.uploads.parts.create(uploadId, { ...params }) -> UploadPart +- client.uploads.parts.create(uploadID, { ...params }) -> UploadPart diff --git a/ecosystem-tests/browser-direct-import/.gitignore b/ecosystem-tests/browser-direct-import/.gitignore new file mode 100644 index 000000000..8225baa4a --- /dev/null +++ b/ecosystem-tests/browser-direct-import/.gitignore @@ -0,0 +1,2 @@ +/node_modules +/dist diff --git a/ecosystem-tests/browser-direct-import/package-lock.json b/ecosystem-tests/browser-direct-import/package-lock.json new file mode 100644 index 000000000..de1f65654 --- /dev/null +++ b/ecosystem-tests/browser-direct-import/package-lock.json @@ -0,0 +1,2194 @@ +{ + "name": "browser-direct-import", + "version": "0.0.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "browser-direct-import", + "version": "0.0.1", + "devDependencies": { + "fastest-levenshtein": "^1.0.16", + "puppeteer": "^23.4.0", + "sirv-cli": "^3.0.0", + "start-server-and-test": "^2.0.0", + "ts-node": "^10.9.1", + "typescript": "^4.7.4" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", + "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.24.7", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", + "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", + "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.24.7", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@hapi/hoek": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", + "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==", + "dev": true + }, + "node_modules/@hapi/topo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", + "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", + "dev": true, + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "node_modules/@polka/url": { + "version": "1.0.0-next.28", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.28.tgz", + "integrity": "sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@puppeteer/browsers": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.4.0.tgz", + "integrity": "sha512-x8J1csfIygOwf6D6qUAZ0ASk3z63zPb7wkNeHRerCMh82qWKUrOgkuP005AJC8lDL6/evtXETGEJVcwykKT4/g==", + "dev": true, + "dependencies": { + "debug": "^4.3.6", + "extract-zip": "^2.0.1", + "progress": "^2.0.3", + "proxy-agent": "^6.4.0", + "semver": "^7.6.3", + "tar-fs": "^3.0.6", + "unbzip2-stream": "^1.4.3", + "yargs": "^17.7.2" + }, + "bin": { + "browsers": "lib/cjs/main-cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@puppeteer/browsers/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@puppeteer/browsers/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/@puppeteer/browsers/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@sideway/address": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz", + "integrity": "sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==", + "dev": true, + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@sideway/formula": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", + "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==", + "dev": true + }, + "node_modules/@sideway/pinpoint": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", + "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==", + "dev": true + }, + "node_modules/@tootallnate/quickjs-emscripten": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", + "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==", + "dev": true + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true + }, + "node_modules/@types/node": { + "version": "20.5.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.7.tgz", + "integrity": "sha512-dP7f3LdZIysZnmvP3ANJYTSwg+wLLl8p7RqniVlV7j+oXSXAbt9h0WIBFmJy5inWZoX9wZN6eXx+YXd9Rh3RBA==", + "dev": true + }, + "node_modules/@types/yauzl": { + "version": "2.10.3", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", + "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", + "dev": true, + "optional": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/acorn": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/agent-base": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz", + "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==", + "dev": true, + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "dev": true + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/ast-types": { + "version": "0.13.4", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", + "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", + "dev": true, + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true + }, + "node_modules/axios": { + "version": "1.7.8", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.8.tgz", + "integrity": "sha512-Uu0wb7KNqK2t5K+YQyVCLM76prD5sRFjKHbJYCP1J7JFGEQ6nN7HWn9+04LAeiJ3ji54lgS/gZCH1oxyrf1SPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/axios/node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/b4a": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.6.tgz", + "integrity": "sha512-5Tk1HLk6b6ctmjIkAcU/Ujv/1WqiDl0F0JdRCR80VsOcUlHcu7pWeWRlOqQLHfDEsVx9YH/aif5AG4ehoCtTmg==", + "dev": true + }, + "node_modules/bare-events": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.4.2.tgz", + "integrity": "sha512-qMKFd2qG/36aA4GwvKq8MxnPgCQAmBWmSyLWsJcbn8v03wvIPQ/hG1Ms8bPzndZxMDoHpxez5VOS+gC9Yi24/Q==", + "dev": true, + "optional": true + }, + "node_modules/bare-fs": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-2.3.5.tgz", + "integrity": "sha512-SlE9eTxifPDJrT6YgemQ1WGFleevzwY+XAP1Xqgl56HtcrisC2CHCZ2tq6dBpcH2TnNxwUEUGhweo+lrQtYuiw==", + "dev": true, + "optional": true, + "dependencies": { + "bare-events": "^2.0.0", + "bare-path": "^2.0.0", + "bare-stream": "^2.0.0" + } + }, + "node_modules/bare-os": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-2.4.4.tgz", + "integrity": "sha512-z3UiI2yi1mK0sXeRdc4O1Kk8aOa/e+FNWZcTiPB/dfTWyLypuE99LibgRaQki914Jq//yAWylcAt+mknKdixRQ==", + "dev": true, + "optional": true + }, + "node_modules/bare-path": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-2.1.3.tgz", + "integrity": "sha512-lh/eITfU8hrj9Ru5quUp0Io1kJWIk1bTjzo7JH1P5dWmQ2EL4hFUlfI8FonAhSlgIfhn63p84CDY/x+PisgcXA==", + "dev": true, + "optional": true, + "dependencies": { + "bare-os": "^2.1.0" + } + }, + "node_modules/bare-stream": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.3.0.tgz", + "integrity": "sha512-pVRWciewGUeCyKEuRxwv06M079r+fRjAQjBEK2P6OYGrO43O+Z0LrPZZEjlc4mB6C2RpZ9AxJ1s7NLEtOHO6eA==", + "dev": true, + "optional": true, + "dependencies": { + "b4a": "^1.6.6", + "streamx": "^2.20.0" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/basic-ftp": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.5.tgz", + "integrity": "sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/check-more-types": { + "version": "2.24.0", + "resolved": "https://registry.npmjs.org/check-more-types/-/check-more-types-2.24.0.tgz", + "integrity": "sha512-Pj779qHxV2tuapviy1bSZNEL1maXr13bPYpsvSDB68HlYcYuhlDrmGd63i0JHMCLKzc7rUSNIrpdJlhVlNwrxA==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/chromium-bidi": { + "version": "0.6.5", + "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.6.5.tgz", + "integrity": "sha512-RuLrmzYrxSb0s9SgpB+QN5jJucPduZQ/9SIe76MDxYJuecPW5mxMdacJ1f4EtgiV+R0p3sCkznTMvH0MPGFqjA==", + "dev": true, + "dependencies": { + "mitt": "3.0.1", + "urlpattern-polyfill": "10.0.0", + "zod": "3.23.8" + }, + "peerDependencies": { + "devtools-protocol": "*" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/console-clear": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/console-clear/-/console-clear-1.1.1.tgz", + "integrity": "sha512-pMD+MVR538ipqkG5JXeOEbKWS5um1H4LUUccUQG68qpeqBYbzYy79Gh55jkd2TtPdRfUaLWdv6LPP//5Zt0aPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/data-uri-to-buffer": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", + "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==", + "dev": true, + "engines": { + "node": ">= 14" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/degenerator": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz", + "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==", + "dev": true, + "dependencies": { + "ast-types": "^0.13.4", + "escodegen": "^2.1.0", + "esprima": "^4.0.1" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/devtools-protocol": { + "version": "0.0.1342118", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1342118.tgz", + "integrity": "sha512-75fMas7PkYNDTmDyb6PRJCH7ILmHLp+BhrZGeMsa4bCh40DTxgCz2NRy5UDzII4C5KuD0oBMZ9vXKhEl6UD/3w==", + "dev": true + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", + "dev": true + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "dev": true, + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/escodegen/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/event-stream": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", + "integrity": "sha512-QHpkERcGsR0T7Qm3HNJSyXKEEj8AHNxkY3PK8TS2KJvQ7NiSHe3DDpwVKKtoYprL/AreyzFBeIkBIWChAqn60g==", + "dev": true, + "dependencies": { + "duplexer": "~0.1.1", + "from": "~0", + "map-stream": "~0.1.0", + "pause-stream": "0.0.11", + "split": "0.3", + "stream-combiner": "~0.0.4", + "through": "~2.3.1" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/execa/node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + }, + "bin": { + "extract-zip": "cli.js" + }, + "engines": { + "node": ">= 10.17.0" + }, + "optionalDependencies": { + "@types/yauzl": "^2.9.1" + } + }, + "node_modules/fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", + "dev": true + }, + "node_modules/fastest-levenshtein": { + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", + "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==", + "dev": true, + "engines": { + "node": ">= 4.9.1" + } + }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "dev": true, + "dependencies": { + "pend": "~1.2.0" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/from": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", + "integrity": "sha512-twe20eF1OxVxp/ML/kq2p1uc6KvFK/+vs8WjEbeKmV2He22MKm7YF2ANIt+EOqhJ5L3K/SuuPhk0hWQDjOM23g==", + "dev": true + }, + "node_modules/fs-extra": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", + "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-port": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz", + "integrity": "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dev": true, + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-uri": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.3.tgz", + "integrity": "sha512-BzUrJBS9EcUb4cFol8r4W3v1cPsSyajLSthNkz5BxbpDcHN5tIrM10E2eNvfnvBn3DaT3DUgx0OpsBKkaOpanw==", + "dev": true, + "dependencies": { + "basic-ftp": "^5.0.2", + "data-uri-to-buffer": "^6.0.2", + "debug": "^4.3.4", + "fs-extra": "^11.2.0" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz", + "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==", + "dev": true, + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ip-address": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", + "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "dev": true, + "dependencies": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/ip-address/node_modules/jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", + "dev": true + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/joi": { + "version": "17.11.0", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.11.0.tgz", + "integrity": "sha512-NgB+lZLNoqISVy1rZocE9PZI36bL/77ie924Ri43yEvi9GUUMPeyVIr8KdFTMUlby1p0PBYMk9spIxEUQYqrJQ==", + "dev": true, + "dependencies": { + "@hapi/hoek": "^9.0.0", + "@hapi/topo": "^5.0.0", + "@sideway/address": "^4.1.3", + "@sideway/formula": "^3.0.1", + "@sideway/pinpoint": "^2.0.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/lazy-ass": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/lazy-ass/-/lazy-ass-1.6.0.tgz", + "integrity": "sha512-cc8oEVoctTvsFZ/Oje/kGnHbpWHYBe8IAJe4C0QNc3t8uM/0Y8+erSz/7Y1ALuXTEZTMvxXwO6YbX1ey3ujiZw==", + "dev": true, + "engines": { + "node": "> 0.8" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "node_modules/local-access": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/local-access/-/local-access-1.1.0.tgz", + "integrity": "sha512-XfegD5pyTAfb+GY6chk283Ox5z8WexG56OvM06RWLpAc/UHozO8X6xAxEkIitZOtsSMM1Yr3DkHgW5W+onLhCw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "node_modules/map-stream": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz", + "integrity": "sha512-CkYQrPYZfWnu/DAmVCpTSX/xHpKZ80eKh2lAkyA6AJTef6bW+6JpbQZN5rofum7da+SyN1bi5ctTm+lTfcCW3g==", + "dev": true + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mitt": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", + "dev": true + }, + "node_modules/mri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/mrmime": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz", + "integrity": "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/netmask": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", + "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pac-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.0.2.tgz", + "integrity": "sha512-BFi3vZnO9X5Qt6NRz7ZOaPja3ic0PhlsmCRYLOpN11+mWBCR6XJDqW5RF3j8jm4WGGQZtBA+bTfxYzeKW73eHg==", + "dev": true, + "dependencies": { + "@tootallnate/quickjs-emscripten": "^0.23.0", + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "get-uri": "^6.0.1", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.5", + "pac-resolver": "^7.0.1", + "socks-proxy-agent": "^8.0.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/pac-resolver": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz", + "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==", + "dev": true, + "dependencies": { + "degenerator": "^5.0.0", + "netmask": "^2.0.2" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/pause-stream": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", + "integrity": "sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==", + "dev": true, + "dependencies": { + "through": "~2.3" + } + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "dev": true + }, + "node_modules/picocolors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", + "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==", + "dev": true + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/proxy-agent": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.4.0.tgz", + "integrity": "sha512-u0piLU+nCOHMgGjRbimiXmA9kM/L9EHh3zL81xCdp7m+Y2pHIsnmbdDoEDoAz5geaonNR6q6+yOPQs6n4T6sBQ==", + "dev": true, + "dependencies": { + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "http-proxy-agent": "^7.0.1", + "https-proxy-agent": "^7.0.3", + "lru-cache": "^7.14.1", + "pac-proxy-agent": "^7.0.1", + "proxy-from-env": "^1.1.0", + "socks-proxy-agent": "^8.0.2" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/proxy-agent/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "dev": true + }, + "node_modules/ps-tree": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/ps-tree/-/ps-tree-1.2.0.tgz", + "integrity": "sha512-0VnamPPYHl4uaU/nSFeZZpR21QAWRz+sRv4iW9+v/GS/J5U5iZB5BNN6J0RMoOvdx2gWM2+ZFMIm58q24e4UYA==", + "dev": true, + "dependencies": { + "event-stream": "=3.3.4" + }, + "bin": { + "ps-tree": "bin/ps-tree.js" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/pump": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz", + "integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/puppeteer": { + "version": "23.4.0", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-23.4.0.tgz", + "integrity": "sha512-FxgFFJI7NAsX8uebiEDSjS86vufz9TaqERQHShQT0lCbSRI3jUPEcz/0HdwLiYvfYNsc1zGjqY3NsGZya4PvUA==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "@puppeteer/browsers": "2.4.0", + "chromium-bidi": "0.6.5", + "cosmiconfig": "^9.0.0", + "devtools-protocol": "0.0.1342118", + "puppeteer-core": "23.4.0", + "typed-query-selector": "^2.12.0" + }, + "bin": { + "puppeteer": "lib/cjs/puppeteer/node/cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/puppeteer-core": { + "version": "23.4.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-23.4.0.tgz", + "integrity": "sha512-fqkIP5FOcb38jfBj/OcBz1wFaI9nk40uQKSORvnXws6wCbep2dg8yxZ3ddJxBIfQsxoiEOvnrykFinUScrB/ew==", + "dev": true, + "dependencies": { + "@puppeteer/browsers": "2.4.0", + "chromium-bidi": "0.6.5", + "debug": "^4.3.7", + "devtools-protocol": "0.0.1342118", + "typed-query-selector": "^2.12.0", + "ws": "^8.18.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/puppeteer-core/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/puppeteer-core/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/puppeteer/node_modules/cosmiconfig": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", + "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", + "dev": true, + "dependencies": { + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/puppeteer/node_modules/typescript": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz", + "integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==", + "dev": true, + "optional": true, + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/queue-tick": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", + "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==", + "dev": true + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dev": true, + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/sade": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", + "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "mri": "^1.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/semiver": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/semiver/-/semiver-1.1.0.tgz", + "integrity": "sha512-QNI2ChmuioGC1/xjyYwyZYADILWyW6AmS1UH6gDj/SFUUUS4MBAWs/7mxnkRPc/F4iHezDP+O8t0dO8WHiEOdg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/sirv": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.0.tgz", + "integrity": "sha512-BPwJGUeDaDCHihkORDchNyyTvWFhcusy1XMmhEVTQTwGeybFbp8YEmB+njbPnth1FibULBSBVwCQni25XlCUDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/sirv-cli": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/sirv-cli/-/sirv-cli-3.0.0.tgz", + "integrity": "sha512-p88yHl8DmTOUJroRiW2o9ezJc/YRLxphBydX2NGQc3naKBA09B3EM4Q/yaN8FYF0e50fRSZP7dyatr72b1u5Jw==", + "dev": true, + "license": "MIT", + "dependencies": { + "console-clear": "^1.1.0", + "get-port": "^5.1.1", + "kleur": "^4.1.4", + "local-access": "^1.0.1", + "sade": "^1.6.0", + "semiver": "^1.0.0", + "sirv": "^3.0.0", + "tinydate": "^1.0.0" + }, + "bin": { + "sirv": "bin.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true, + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", + "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", + "dev": true, + "dependencies": { + "ip-address": "^9.0.5", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "8.0.4", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.4.tgz", + "integrity": "sha512-GNAq/eg8Udq2x0eNiFkr9gRg5bA7PXEWagQdeRX4cPSG+X/8V38v637gim9bjFptMk1QWsCTr0ttrJEiXbNnRw==", + "dev": true, + "dependencies": { + "agent-base": "^7.1.1", + "debug": "^4.3.4", + "socks": "^2.8.3" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/split": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz", + "integrity": "sha512-wD2AeVmxXRBoX44wAycgjVpMhvbwdI2aZjCkvfNcH1YqHQvJVa1duWc73OyVGJUc05fhFaTZeQ/PYsrmyH0JVA==", + "dev": true, + "dependencies": { + "through": "2" + }, + "engines": { + "node": "*" + } + }, + "node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", + "dev": true + }, + "node_modules/start-server-and-test": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/start-server-and-test/-/start-server-and-test-2.0.3.tgz", + "integrity": "sha512-QsVObjfjFZKJE6CS6bSKNwWZCKBG6975/jKRPPGFfFh+yOQglSeGXiNWjzgQNXdphcBI9nXbyso9tPfX4YAUhg==", + "dev": true, + "dependencies": { + "arg": "^5.0.2", + "bluebird": "3.7.2", + "check-more-types": "2.24.0", + "debug": "4.3.4", + "execa": "5.1.1", + "lazy-ass": "1.6.0", + "ps-tree": "1.2.0", + "wait-on": "7.2.0" + }, + "bin": { + "server-test": "src/bin/start.js", + "start-server-and-test": "src/bin/start.js", + "start-test": "src/bin/start.js" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/stream-combiner": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz", + "integrity": "sha512-rT00SPnTVyRsaSz5zgSPma/aHSOic5U1prhYdRy5HS2kTZviFpmDgzilbtsJsxiroqACmayynDN/9VzIbX5DOw==", + "dev": true, + "dependencies": { + "duplexer": "~0.1.1" + } + }, + "node_modules/streamx": { + "version": "2.20.1", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.20.1.tgz", + "integrity": "sha512-uTa0mU6WUC65iUvzKH4X9hEdvSW7rbPxPtwfWiLMSj3qTdQbAiUboZTxauKfpFuGIGa1C2BYijZ7wgdUXICJhA==", + "dev": true, + "dependencies": { + "fast-fifo": "^1.3.2", + "queue-tick": "^1.0.1", + "text-decoder": "^1.1.0" + }, + "optionalDependencies": { + "bare-events": "^2.2.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/tar-fs": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.6.tgz", + "integrity": "sha512-iokBDQQkUyeXhgPYaZxmczGPhnhXZ0CmrqI+MOb/WFGS9DW5wnfrLgtjUJBvz50vQ3qfRwJ62QVoCFu8mPVu5w==", + "dev": true, + "dependencies": { + "pump": "^3.0.0", + "tar-stream": "^3.1.5" + }, + "optionalDependencies": { + "bare-fs": "^2.1.1", + "bare-path": "^2.1.0" + } + }, + "node_modules/tar-stream": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", + "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", + "dev": true, + "dependencies": { + "b4a": "^1.6.4", + "fast-fifo": "^1.2.0", + "streamx": "^2.15.0" + } + }, + "node_modules/text-decoder": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.0.tgz", + "integrity": "sha512-n1yg1mOj9DNpk3NeZOx7T6jchTbyJS3i3cucbNN6FcdPriMZx7NsgrGpWWdWZZGxD7ES1XB+3uoqHMgOKaN+fg==", + "dev": true, + "dependencies": { + "b4a": "^1.6.4" + } + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", + "dev": true + }, + "node_modules/tinydate": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/tinydate/-/tinydate-1.3.0.tgz", + "integrity": "sha512-7cR8rLy2QhYHpsBDBVYnnWXm8uRTr38RoZakFSW7Bs7PzfMPNZthuMLkwqZv7MTu8lhQ91cOFYS5a7iFj2oR3w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/ts-node/node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + }, + "node_modules/typed-query-selector": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/typed-query-selector/-/typed-query-selector-2.12.0.tgz", + "integrity": "sha512-SbklCd1F0EiZOyPiW192rrHZzZ5sBijB6xM+cpmrwDqObvdtunOHHIk9fCGsoK5JVIYXoyEp4iEdE3upFH3PAg==", + "dev": true + }, + "node_modules/typescript": { + "version": "4.7.4", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", + "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/unbzip2-stream": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", + "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", + "dev": true, + "dependencies": { + "buffer": "^5.2.1", + "through": "^2.3.8" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/urlpattern-polyfill": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/urlpattern-polyfill/-/urlpattern-polyfill-10.0.0.tgz", + "integrity": "sha512-H/A06tKD7sS1O1X2SshBVeA5FLycRpjqiBeqGKmBwBDBy28EnRjORxTNe269KSSr5un5qyWi1iL61wLxpd+ZOg==", + "dev": true + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, + "node_modules/wait-on": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-7.2.0.tgz", + "integrity": "sha512-wCQcHkRazgjG5XoAq9jbTMLpNIjoSlZslrJ2+N9MxDsGEv1HnFoVjOCexL0ESva7Y9cu350j+DWADdk54s4AFQ==", + "dev": true, + "dependencies": { + "axios": "^1.6.1", + "joi": "^17.11.0", + "lodash": "^4.17.21", + "minimist": "^1.2.8", + "rxjs": "^7.8.1" + }, + "bin": { + "wait-on": "bin/wait-on" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "dev": true, + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/zod": { + "version": "3.23.8", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz", + "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + } + } +} diff --git a/ecosystem-tests/browser-direct-import/package.json b/ecosystem-tests/browser-direct-import/package.json new file mode 100644 index 000000000..579eef370 --- /dev/null +++ b/ecosystem-tests/browser-direct-import/package.json @@ -0,0 +1,19 @@ +{ + "name": "browser-direct-import", + "version": "0.0.1", + "private": true, + "scripts": { + "tsc": "tsc --noEmit", + "test": "ts-node src/test.ts", + "test:ci": "start-server-and-test serve http://localhost:8081 test", + "serve": "sirv -q public --port 8081" + }, + "devDependencies": { + "fastest-levenshtein": "^1.0.16", + "puppeteer": "^23.4.0", + "sirv-cli": "^3.0.0", + "start-server-and-test": "^2.0.0", + "ts-node": "^10.9.1", + "typescript": "^4.7.4" + } +} diff --git a/ecosystem-tests/browser-direct-import/public/index.html b/ecosystem-tests/browser-direct-import/public/index.html new file mode 100644 index 000000000..1e121c30c --- /dev/null +++ b/ecosystem-tests/browser-direct-import/public/index.html @@ -0,0 +1,11 @@ + + + + + Package in the Browser + + +
Running tests...
+ + + diff --git a/ecosystem-tests/browser-direct-import/public/index.js b/ecosystem-tests/browser-direct-import/public/index.js new file mode 100644 index 000000000..eb3b924bf --- /dev/null +++ b/ecosystem-tests/browser-direct-import/public/index.js @@ -0,0 +1,227 @@ +// @ts-check +import OpenAI, { toFile } from './node_modules/openai/index.mjs'; +import { distance } from './node_modules/fastest-levenshtein/esm/mod.js'; + +/** @typedef {{ path: string[]; run: () => any; timeout?: number; }} TestCase */ + +/** @type {TestCase[]} */ +const tests = []; + +/** @typedef {{ path: string[]; passed: boolean; error?: string }} TestResult */ + +async function runTests() { + /** @type {TestResult[]} */ + const results = []; + function displayResults() { + let pre = document.getElementById('results'); + if (!pre) { + pre = document.createElement('pre'); + pre.id = 'results'; + document.body.appendChild(pre); + } + pre.innerText = JSON.stringify(results, null, 2); + } + for (const { path, run, timeout } of tests) { + console.log('running', ...path); + try { + await Promise.race([ + run(), + new Promise((_, reject) => + setTimeout(() => reject(new Error(`Test timed out after ${timeout} ms`)), timeout), + ), + ]); + console.log('passed ', ...path); + results.push({ path, passed: true }); + } catch (error) { + console.log('error ', ...path); + console.error(error); + results.push({ path, passed: false, error: error instanceof Error ? error.stack : String(error) }); + } + displayResults(); + } + const runningEl = document.getElementById('running'); + if (runningEl) runningEl.remove(); +} + +/** @type {string[]} */ +const testPath = []; + +/** + * @param {string} description + * @param {() => void} handler + */ +function describe(description, handler) { + testPath.push(description); + try { + handler(); + } finally { + testPath.pop(); + } +} + +/** + * @param {string} description + * @param {() => any} run + * @param {number} [timeout=60000] + */ +function it(description, run, timeout = 60000) { + tests.push({ path: [...testPath, description], run, timeout }); +} + +/** + * @param {any} received + * @returns {{ + * toEqual: (expected: any) => void; + * toBeSimilarTo: (comparedTo: string, expectedDistance: number) => void; + * }} + */ +function expect(received) { + return { + toEqual(expected) { + if (!Object.is(received, expected)) { + throw new Error( + [`Received: ${JSON.stringify(received)}`, `Expected: ${JSON.stringify(expected)}`].join('\n'), + ); + } + }, + toBeSimilarTo(comparedTo, expectedDistance) { + const actualDistance = distance(received, comparedTo); + if (actualDistance < expectedDistance) return; + + throw new Error( + [ + `Received: ${JSON.stringify(received)}`, + `Expected: ${JSON.stringify(comparedTo)}`, + `Expected distance: ${expectedDistance}`, + `Received distance: ${actualDistance}`, + ].join('\n'), + ); + }, + }; +} + +const url = 'https://audio-samples.github.io/samples/mp3/blizzard_biased/sample-1.mp3'; +const filename = 'sample-1.mp3'; + +const correctAnswer = + 'It was anxious to find him no one that expectation of a man who were giving his father enjoyment. But he was avoided in sight in the minister to which indeed,'; +const model = 'whisper-1'; + +const params = new URLSearchParams(location.search); + +const client = new OpenAI({ apiKey: params.get('apiKey') ?? undefined, dangerouslyAllowBrowser: true }); + +async function typeTests() { + // @ts-expect-error this should error if the `Uploadable` type was resolved correctly + await client.audio.transcriptions.create({ file: { foo: true }, model: 'whisper-1' }); + // @ts-expect-error this should error if the `Uploadable` type was resolved correctly + await client.audio.transcriptions.create({ file: null, model: 'whisper-1' }); + // @ts-expect-error this should error if the `Uploadable` type was resolved correctly + await client.audio.transcriptions.create({ file: 'test', model: 'whisper-1' }); +} + +it(`raw response`, async function () { + const response = await client.chat.completions + .create({ + model: 'gpt-4', + messages: [{ role: 'user', content: 'Say this is a test' }], + }) + .asResponse(); + + // test that we can use web Response API + const { body } = response; + if (!body) throw new Error('expected response.body to be defined'); + + const reader = body.getReader(); + /** @type {Uint8Array[]} */ + const chunks = []; + let result; + do { + result = await reader.read(); + if (!result.done) chunks.push(result.value); + } while (!result.done); + + reader.releaseLock(); + + let offset = 0; + const merged = new Uint8Array(chunks.reduce((total, chunk) => total + chunk.length, 0)); + for (const chunk of chunks) { + merged.set(chunk, offset); + offset += chunk.length; + } + + const json = /** @type {OpenAI.ChatCompletion} */ (JSON.parse(new TextDecoder().decode(merged))); + expect(json.choices[0]?.message.content || '').toBeSimilarTo('This is a test', 10); +}); + +it(`streaming works`, async function () { + const stream = await client.chat.completions.create({ + model: 'gpt-4', + messages: [{ role: 'user', content: 'Say this is a test' }], + stream: true, + }); + const chunks = []; + for await (const part of stream) { + chunks.push(part); + } + expect(chunks.map((c) => c.choices[0]?.delta.content || '').join('')).toBeSimilarTo('This is a test', 10); +}); + +if (typeof File !== 'undefined') { + it('handles builtinFile', async function () { + const file = await fetch(url) + .then((x) => x.arrayBuffer()) + .then((x) => new File([x], filename)); + + const result = await client.audio.transcriptions.create({ file, model }); + expect(result.text).toBeSimilarTo(correctAnswer, 12); + }); +} + +it('handles Response', async function () { + const file = await fetch(url); + + const result = await client.audio.transcriptions.create({ file, model }); + expect(result.text).toBeSimilarTo(correctAnswer, 12); +}); + +const fineTune = `{"prompt": "", "completion": ""}`; + +describe('toFile', () => { + if (typeof Blob !== 'undefined') { + it('handles builtin Blob', async function () { + const result = await client.files.create({ + file: await toFile( + // @ts-ignore avoid DOM lib for testing purposes + new Blob([new TextEncoder().encode(fineTune)]), + 'finetune.jsonl', + ), + purpose: 'fine-tune', + }); + expect(result.filename).toEqual('finetune.jsonl'); + }); + } + it('handles Uint8Array', async function () { + const result = await client.files.create({ + file: await toFile(new TextEncoder().encode(fineTune), 'finetune.jsonl'), + purpose: 'fine-tune', + }); + expect(result.filename).toEqual('finetune.jsonl'); + }); + it('handles ArrayBuffer', async function () { + const result = await client.files.create({ + file: await toFile(new TextEncoder().encode(fineTune).buffer, 'finetune.jsonl'), + purpose: 'fine-tune', + }); + expect(result.filename).toEqual('finetune.jsonl'); + }); + it('handles DataView', async function () { + const result = await client.files.create({ + file: await toFile(new DataView(new TextEncoder().encode(fineTune).buffer), 'finetune.jsonl'), + purpose: 'fine-tune', + }); + expect(result.filename).toEqual('finetune.jsonl'); + }); +}); + +runTests(); \ No newline at end of file diff --git a/ecosystem-tests/browser-direct-import/src/test.ts b/ecosystem-tests/browser-direct-import/src/test.ts new file mode 100644 index 000000000..ba26ea165 --- /dev/null +++ b/ecosystem-tests/browser-direct-import/src/test.ts @@ -0,0 +1,75 @@ +import puppeteer from 'puppeteer'; + +(async () => { + const browser = await puppeteer.launch({ + args: ['--no-sandbox'], + }); + let page; + try { + page = await browser.newPage(); + function debugEvent(subj: string) { + return subj.padEnd('requestfailed'.length); + } + page + .on('console', (message) => + console.error( + `${debugEvent('console')} ${message + .type() + .substr(0, 'warning'.length) + .toUpperCase() + .padEnd('warning'.length)} ${message.text()}`, + ), + ) + .on('pageerror', ({ message }) => console.error(`${debugEvent('pageerror')} ${message}`)) + .on('response', (response) => + console.error(`${debugEvent('response')} ${response.status()} ${response.url()}`), + ) + .on('requestfailed', (request) => + console.error(`${debugEvent('requestfailed')} ${request.failure()?.errorText} ${request.url()}`), + ); + + const apiKey = process.env.OPENAI_API_KEY; + + if (!apiKey) throw new Error('missing process.env.OPENAI_API_KEY'); + + // Navigate the page to a URL + await page.goto(`http://localhost:8081/index.html?apiKey=${apiKey}`); + + await page.waitForSelector('#running', { timeout: 15000 }); + + let start = Date.now(); + while ((await page.$('#running')) != null && Date.now() - start < 3 * 60000) { + await new Promise((r) => setTimeout(r, 1000)); + } + + let results; + const resultsEl = await page.$('#results'); + if (resultsEl) { + const text = await page.evaluate((el) => el.textContent, resultsEl); + results = text ? JSON.parse(text) : undefined; + } + + if (!Array.isArray(results)) { + throw new Error(`failed to get test results from page`); + } + const failed = results.filter((r) => !r.passed); + if (failed.length) { + throw new Error( + `${failed.length} of ${results.length} tests failed: ${JSON.stringify(failed, null, 2)}`, + ); + } + console.log(`${results.length} tests passed!`); + } catch (error) { + if (page) { + try { + const html = await page.evaluate(() => document.body.innerHTML); + console.error(`\n====================\nBODY HTML\n====================\n\n${html}\n\n`); + } catch (error) { + console.error(`failed to get body HTML for debugging`, error); + } + } + throw error; + } finally { + await browser.close(); + } +})(); diff --git a/ecosystem-tests/browser-direct-import/tsconfig.json b/ecosystem-tests/browser-direct-import/tsconfig.json new file mode 100644 index 000000000..8a1b55791 --- /dev/null +++ b/ecosystem-tests/browser-direct-import/tsconfig.json @@ -0,0 +1,22 @@ +{ + "compilerOptions": { + "module": "commonjs", + "strict": true, + "noImplicitReturns": true, + "removeComments": true, + "preserveConstEnums": true, + "sourceMap": true, + "declaration": true, + "skipLibCheck": false, + "target": "es2015", + "lib": ["es2017", "dom"], + "outDir": "dist", + "rootDir": "./", + "baseUrl": ".", + "paths": { + "*": ["types/*"] + } + }, + "include": ["src/**/*", "public/index.js"], + "exclude": ["node_modules/*"] +} diff --git a/ecosystem-tests/bun/bun.lockb b/ecosystem-tests/bun/bun.lockb index 4ece80c92..a01f1617e 100755 Binary files a/ecosystem-tests/bun/bun.lockb and b/ecosystem-tests/bun/bun.lockb differ diff --git a/ecosystem-tests/bun/openai.test.ts b/ecosystem-tests/bun/openai.test.ts index 979a4962f..f8facc521 100644 --- a/ecosystem-tests/bun/openai.test.ts +++ b/ecosystem-tests/bun/openai.test.ts @@ -43,6 +43,20 @@ test(`basic request works`, async function () { expectSimilar(completion.choices[0]?.message?.content, 'This is a test', 10); }); +test(`proxied request works`, async function () { + const client = new OpenAI({ + fetchOptions: { + proxy: process.env['ECOSYSTEM_TESTS_PROXY'], + }, + }); + + const completion = await client.chat.completions.create({ + model: 'gpt-4', + messages: [{ role: 'user', content: 'Say this is a test' }], + }); + expectSimilar(completion.choices[0]?.message?.content, 'This is a test', 10); +}); + test(`raw response`, async function () { const response = await client.chat.completions .create({ @@ -117,6 +131,14 @@ test('handles fs.ReadStream', async function () { expectSimilar(result.text, correctAnswer, 12); }); +test('handles Bun.File', async function () { + const result = await client.audio.transcriptions.create({ + file: Bun.file('sample1.mp3'), + model, + }); + expectSimilar(result.text, correctAnswer, 12); +}); + const fineTune = `{"prompt": "", "completion": ""}`; // @ts-ignore avoid DOM lib for testing purposes diff --git a/ecosystem-tests/bun/package.json b/ecosystem-tests/bun/package.json index 5a75b1eb2..35660b7f9 100644 --- a/ecosystem-tests/bun/package.json +++ b/ecosystem-tests/bun/package.json @@ -10,7 +10,7 @@ }, "devDependencies": { "fastest-levenshtein": "^1.0.16", - "bun-types": "latest", + "bun-types": "^1.2.4", "typescript": "5.0.4" } } diff --git a/ecosystem-tests/bun/tsconfig.json b/ecosystem-tests/bun/tsconfig.json index 69a17ce99..f428d6b10 100644 --- a/ecosystem-tests/bun/tsconfig.json +++ b/ecosystem-tests/bun/tsconfig.json @@ -9,7 +9,7 @@ "allowImportingTsExtensions": true, "strict": true, "downlevelIteration": true, - "skipLibCheck": false, + "skipLibCheck": true, "jsx": "preserve", "allowSyntheticDefaultImports": true, "forceConsistentCasingInFileNames": true, diff --git a/ecosystem-tests/cli.ts b/ecosystem-tests/cli.ts index 00120e5f9..9781c2b03 100644 --- a/ecosystem-tests/cli.ts +++ b/ecosystem-tests/cli.ts @@ -3,10 +3,8 @@ import execa from 'execa'; import yargs from 'yargs'; import assert from 'assert'; import path from 'path'; - -// @ts-ignore -var SegfaultHandler = require('segfault-handler'); -SegfaultHandler.registerHandler('crash.log'); +import { createServer } from 'http'; +import { connect } from 'net'; const TAR_NAME = 'openai.tgz'; const PACK_FOLDER = '.pack'; @@ -25,32 +23,31 @@ const projectRunners = { 'node-ts-cjs': defaultNodeRunner, 'node-ts-cjs-web': defaultNodeRunner, 'node-ts-cjs-auto': defaultNodeRunner, - 'node-ts4.5-jest27': defaultNodeRunner, + 'node-ts4.5-jest28': defaultNodeRunner, 'node-ts-esm': defaultNodeRunner, 'node-ts-esm-web': defaultNodeRunner, 'node-ts-esm-auto': defaultNodeRunner, - 'node-ts-es2020': async () => { - await installPackage(); - await run('npm', ['run', 'tsc']); - await run('npm', ['run', 'main']); - }, 'node-js': async () => { await installPackage(); await run('node', ['test.js']); }, - 'nodenext-tsup': async () => { + 'ts-browser-webpack': async () => { await installPackage(); + + await run('npm', ['run', 'tsc']); await run('npm', ['run', 'build']); if (state.live) { - await run('npm', ['run', 'main']); + await run('npm', ['run', 'test:ci']); } }, - 'ts-browser-webpack': async () => { + 'browser-direct-import': async () => { await installPackage(); + await fs.rm('public/node_modules', { force: true }); + await fs.symlink('../node_modules', 'public/node_modules'); + await run('npm', ['run', 'tsc']); - await run('npm', ['run', 'build']); if (state.live) { await run('npm', ['run', 'test:ci']); @@ -74,6 +71,7 @@ const projectRunners = { 'cloudflare-worker': async () => { await installPackage(); + await fs.writeFile('.dev.vars', `OPENAI_API_KEY='${process.env['OPENAI_API_KEY']}'`); await run('npm', ['run', 'tsc']); if (state.live) { @@ -99,19 +97,49 @@ const projectRunners = { await run('bun', ['test']); } }, - deno: async () => { - // we don't need to explicitly install the package here - // because our deno setup relies on `rootDir/dist-deno` to exist - // which is an artifact produced from our build process - await run('deno', ['task', 'install', '--unstable-sloppy-imports']); - - if (state.live) await run('deno', ['task', 'test']); - }, + // deno: async () => { + // // we don't need to explicitly install the package here + // // because our deno setup relies on `rootDir/deno` to exist + // // which is an artifact produced from our build process + // await run('deno', ['task', 'install']); + // await run('deno', ['task', 'check']); + // + // if (state.live) await run('deno', ['task', 'test']); + // }, }; let projectNames = Object.keys(projectRunners) as Array; const projectNamesSet = new Set(projectNames); +async function startProxy() { + const proxy = createServer((_req, res) => { + res.end(); + }); + + proxy.on('connect', (req, clientSocket, head) => { + console.log('got proxied connection'); + const serverSocket = connect(443, 'api.openai.com', () => { + clientSocket.write( + 'HTTP/1.1 200 Connection Established\r\n' + 'Proxy-agent: Node.js-Proxy\r\n' + '\r\n', + ); + serverSocket.write(head); + serverSocket.pipe(clientSocket); + clientSocket.pipe(serverSocket); + }); + }); + + await new Promise((resolve) => proxy.listen(0, '127.0.0.1', resolve)); + + const address = proxy.address(); + assert(address && typeof address !== 'string'); + process.env['ECOSYSTEM_TESTS_PROXY'] = 'http://127.0.0.1/' + address.port; + + return () => { + delete process.env['ECOSYSTEM_TESTS_PROXY']; + proxy.close(); + }; +} + function parseArgs() { return yargs(process.argv.slice(2)) .scriptName('ecosystem-tests') @@ -290,112 +318,118 @@ async function main() { await fileCache.cacheFiles(tmpFolderPath); } - if (jobs > 1) { - const queue = [...projectsToRun]; - const runningProjects = new Set(); - - const cursorLeft = '\x1B[G'; - const eraseLine = '\x1B[2K'; - - let progressDisplayed = false; - function clearProgress() { - if (progressDisplayed) { - process.stderr.write(cursorLeft + eraseLine); - progressDisplayed = false; + const stopProxy = await startProxy(); + try { + if (jobs > 1) { + const queue = [...projectsToRun]; + const runningProjects = new Set(); + + const cursorLeft = '\x1B[G'; + const eraseLine = '\x1B[2K'; + + let progressDisplayed = false; + function clearProgress() { + if (progressDisplayed) { + process.stderr.write(cursorLeft + eraseLine); + progressDisplayed = false; + } + } + const spinner = ['|', '/', '-', '\\']; + + function showProgress() { + clearProgress(); + progressDisplayed = true; + const spin = spinner[Math.floor(Date.now() / 500) % spinner.length]; + process.stderr.write( + `${spin} Running ${[...runningProjects].join(', ')}`.substring(0, process.stdout.columns - 3) + + '...', + ); } - } - const spinner = ['|', '/', '-', '\\']; - function showProgress() { - clearProgress(); - progressDisplayed = true; - const spin = spinner[Math.floor(Date.now() / 500) % spinner.length]; - process.stderr.write( - `${spin} Running ${[...runningProjects].join(', ')}`.substring(0, process.stdout.columns - 3) + '...', - ); - } + const progressInterval = setInterval(showProgress, process.stdout.isTTY ? 500 : 5000); + showProgress(); - const progressInterval = setInterval(showProgress, process.stdout.isTTY ? 500 : 5000); - showProgress(); + await Promise.all( + [...Array(jobs).keys()].map(async () => { + while (queue.length) { + const project = queue.shift(); + if (!project) { + break; + } - await Promise.all( - [...Array(jobs).keys()].map(async () => { - while (queue.length) { - const project = queue.shift(); - if (!project) { - break; - } + // preserve interleaved ordering of writes to stdout/stderr + const chunks: { dest: 'stdout' | 'stderr'; data: string | Buffer }[] = []; + try { + runningProjects.add(project); + const child = execa( + 'yarn', + [ + 'tsn', + __filename, + project, + '--skip-pack', + '--noCleanup', + `--retry=${args.retry}`, + ...(args.live ? ['--live'] : []), + ...(args.verbose ? ['--verbose'] : []), + ...(args.deploy ? ['--deploy'] : []), + ...(args.fromNpm ? ['--from-npm'] : []), + ], + { stdio: 'pipe', encoding: 'utf8', maxBuffer: 100 * 1024 * 1024 }, + ); + child.stdout?.on('data', (data) => chunks.push({ dest: 'stdout', data })); + child.stderr?.on('data', (data) => chunks.push({ dest: 'stderr', data })); + + await child; + } catch (error) { + failed.push(project); + } finally { + runningProjects.delete(project); + } - // preserve interleaved ordering of writes to stdout/stderr - const chunks: { dest: 'stdout' | 'stderr'; data: string | Buffer }[] = []; - try { - runningProjects.add(project); - const child = execa( - 'yarn', - [ - 'tsn', - __filename, - project, - '--skip-pack', - '--noCleanup', - `--retry=${args.retry}`, - ...(args.live ? ['--live'] : []), - ...(args.verbose ? ['--verbose'] : []), - ...(args.deploy ? ['--deploy'] : []), - ...(args.fromNpm ? ['--from-npm'] : []), - ], - { stdio: 'pipe', encoding: 'utf8', maxBuffer: 100 * 1024 * 1024 }, - ); - child.stdout?.on('data', (data) => chunks.push({ dest: 'stdout', data })); - child.stderr?.on('data', (data) => chunks.push({ dest: 'stderr', data })); - - await child; - } catch (error) { - failed.push(project); - } finally { - runningProjects.delete(project); - } + if (IS_CI) { + console.log(`::group::${failed.includes(project) ? '❌' : '✅'} ${project}`); + } - if (IS_CI) { - console.log(`::group::${failed.includes(project) ? '❌' : '✅'} ${project}`); + for (const { data } of chunks) { + process.stdout.write(data); + } + if (IS_CI) console.log('::endgroup::'); } + }), + ); - for (const { data } of chunks) { - process.stdout.write(data); - } - if (IS_CI) console.log('::endgroup::'); - } - }), - ); - - clearInterval(progressInterval); - clearProgress(); - } else { - for (const project of projectsToRun) { - const fn = projectRunners[project]; - - await withChdir(path.join(rootDir, 'ecosystem-tests', project), async () => { - console.error('\n'); - console.error(banner(`▶️ ${project}`)); - console.error('\n'); - - try { - await withRetry(fn, project, state.retry, state.retryDelay); + clearInterval(progressInterval); + clearProgress(); + } else { + for (const project of projectsToRun) { + const fn = projectRunners[project]; + + await withChdir(path.join(rootDir, 'ecosystem-tests', project), async () => { console.error('\n'); - console.error(`✅ ${project}`); - } catch (err) { - if (err && (err as any).shortMessage) { - console.error((err as any).shortMessage); - } else { - console.error(err); + console.error(banner(`▶️ ${project}`)); + console.error('\n'); + + try { + await withRetry(fn, project, state.retry, state.retryDelay); + console.error('\n'); + console.error(`✅ ${project}`); + } catch (err) { + if (err && (err as any).shortMessage) { + console.error((err as any).shortMessage); + } else { + console.error(err); + } + console.error('\n'); + console.error(`❌ ${project}`); + failed.push(project); } console.error('\n'); - console.error(`❌ ${project}`); - failed.push(project); - } - console.error('\n'); - }); + }); + } } + } finally { + stopProxy(); } if (!args.noCleanup) { diff --git a/ecosystem-tests/cloudflare-worker/package-lock.json b/ecosystem-tests/cloudflare-worker/package-lock.json index 99d787f75..51cd6aee3 100644 --- a/ecosystem-tests/cloudflare-worker/package-lock.json +++ b/ecosystem-tests/cloudflare-worker/package-lock.json @@ -7,9 +7,6 @@ "": { "name": "cfw", "version": "0.0.0", - "dependencies": { - "node-fetch": "^3.3.1" - }, "devDependencies": { "@cloudflare/workers-types": "^4.20230419.0", "fastest-levenshtein": "^1.0.16", @@ -17,7 +14,7 @@ "start-server-and-test": "^2.0.0", "ts-jest": "^29.1.0", "typescript": "5.0.4", - "wrangler": "^3.85.0" + "wrangler": "^3.74.0" } }, "node_modules/@ampproject/remapping": { @@ -674,9 +671,9 @@ } }, "node_modules/@cloudflare/workerd-darwin-64": { - "version": "1.20241022.0", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20241022.0.tgz", - "integrity": "sha512-1NNYun37myMTgCUiPQEJ0cMal4mKZVTpkD0b2tx9hV70xji+frVJcSK8YVLeUm1P+Rw1d/ct8DMgQuCpsz3Fsw==", + "version": "1.20240909.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-64/-/workerd-darwin-64-1.20240909.0.tgz", + "integrity": "sha512-nJ8jm/6PR8DPzVb4QifNAfSdrFZXNblwIdOhLTU5FpSvFFocmzFX5WgzQagvtmcC9/ZAQyxuf7WynDNyBcoe0Q==", "cpu": [ "x64" ], @@ -690,9 +687,9 @@ } }, "node_modules/@cloudflare/workerd-darwin-arm64": { - "version": "1.20241022.0", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20241022.0.tgz", - "integrity": "sha512-FOO/0P0U82EsTLTdweNVgw+4VOk5nghExLPLSppdOziq6IR5HVgP44Kmq5LdsUeHUhwUmfOh9hzaTpkNzUqKvw==", + "version": "1.20240909.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-darwin-arm64/-/workerd-darwin-arm64-1.20240909.0.tgz", + "integrity": "sha512-gJqKa811oSsoxy9xuoQn7bS0Hr1sY+o3EUORTcEnulG6Kz9NQ6nd8QNdp2Hrk2jmmSqwrNkn+a6PZkWzk6Q0Gw==", "cpu": [ "arm64" ], @@ -706,9 +703,9 @@ } }, "node_modules/@cloudflare/workerd-linux-64": { - "version": "1.20241022.0", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20241022.0.tgz", - "integrity": "sha512-RsNc19BQJG9yd+ngnjuDeG9ywZG+7t1L4JeglgceyY5ViMNMKVO7Zpbsu69kXslU9h6xyQG+lrmclg3cBpnhYA==", + "version": "1.20240909.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-64/-/workerd-linux-64-1.20240909.0.tgz", + "integrity": "sha512-sJrmtccfMg73sZljiBpe4R+lhF58TqzqhF2pQG8HRjyxkzkM1sjpZqfEFaIkNUDqd3/Ibji49fklhPCGXljKSg==", "cpu": [ "x64" ], @@ -722,9 +719,9 @@ } }, "node_modules/@cloudflare/workerd-linux-arm64": { - "version": "1.20241022.0", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20241022.0.tgz", - "integrity": "sha512-x5mUXpKxfsosxcFmcq5DaqLs37PejHYVRsNz1cWI59ma7aC4y4Qn6Tf3i0r9MwQTF/MccP4SjVslMU6m4W7IaA==", + "version": "1.20240909.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-linux-arm64/-/workerd-linux-arm64-1.20240909.0.tgz", + "integrity": "sha512-dTbSdceyRXPOSER+18AwYRbPQG0e/Dwl2trmfMMCETkfJhNLv1fU3FFMJPjfILijKnhTZHSnHCx0+xwHdon2fg==", "cpu": [ "arm64" ], @@ -738,9 +735,9 @@ } }, "node_modules/@cloudflare/workerd-windows-64": { - "version": "1.20241022.0", - "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20241022.0.tgz", - "integrity": "sha512-eBCClx4szCOgKqOlxxbdNszMqQf3MRG1B9BRIqEM/diDfdR9IrZ8l3FaEm+l9gXgPmS6m1NBn40aWuGBl8UTSw==", + "version": "1.20240909.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workerd-windows-64/-/workerd-windows-64-1.20240909.0.tgz", + "integrity": "sha512-/d4BT0kcWFa7Qc0K4K9+cwVQ1qyPNKiO42JZUijlDlco+TYTPkLO3qGEohmwbfMq+BieK7JTMSgjO81ZHpA0HQ==", "cpu": [ "x64" ], @@ -754,9 +751,9 @@ } }, "node_modules/@cloudflare/workers-shared": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/@cloudflare/workers-shared/-/workers-shared-0.7.0.tgz", - "integrity": "sha512-LLQRTqx7lKC7o2eCYMpyc5FXV8d0pUX6r3A+agzhqS9aoR5A6zCPefwQGcvbKx83ozX22ATZcemwxQXn12UofQ==", + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/@cloudflare/workers-shared/-/workers-shared-0.5.4.tgz", + "integrity": "sha512-PNL/0TjKRdUHa1kwgVdqUNJVZ9ez4kacsi8omz+gv859EvJmsVuGiMAClY2YfJnC9LVKhKCcjqmFgKNXG9/IXA==", "dev": true, "dependencies": { "mime": "^3.0.0", @@ -767,9 +764,9 @@ } }, "node_modules/@cloudflare/workers-types": { - "version": "4.20241106.0", - "resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20241106.0.tgz", - "integrity": "sha512-pI4ivacmp+vgNO/siHDsZ6BdITR0LC4Mh/1+yzVLcl9U75pt5DUDCOWOiqIRFXRq6H65DPnJbEPFo3x9UfgofQ==", + "version": "4.20240924.0", + "resolved": "https://registry.npmjs.org/@cloudflare/workers-types/-/workers-types-4.20240924.0.tgz", + "integrity": "sha512-AnoHY0B5rgMv4Lg34mdwfp4+Z9ZZRli8AFO7uY8Q9UchR+HPEMEdaAQ0EswTYQqcVBdarRuYyM0Oeo4hM8Jqog==", "dev": true }, "node_modules/@cspotcode/source-map-support": { @@ -1702,9 +1699,9 @@ "dev": true }, "node_modules/acorn": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", - "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -2236,9 +2233,9 @@ "dev": true }, "node_modules/cookie": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", - "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", + "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", "dev": true, "engines": { "node": ">= 0.6" @@ -2279,24 +2276,6 @@ "node": ">= 8" } }, - "node_modules/data-uri-to-buffer": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", - "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", - "engines": { - "node": ">= 12" - } - }, - "node_modules/date-fns": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz", - "integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==", - "dev": true, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/kossnocorp" - } - }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -2582,28 +2561,6 @@ "bser": "2.1.1" } }, - "node_modules/fetch-blob": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", - "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "paypal", - "url": "https://paypal.me/jimmywarting" - } - ], - "dependencies": { - "node-domexception": "^1.0.0", - "web-streams-polyfill": "^3.0.3" - }, - "engines": { - "node": "^12.20 || >= 14.13" - } - }, "node_modules/fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -2663,17 +2620,6 @@ "node": ">= 6" } }, - "node_modules/formdata-polyfill": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", - "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", - "dependencies": { - "fetch-blob": "^3.1.2" - }, - "engines": { - "node": ">=12.20.0" - } - }, "node_modules/from": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", @@ -3092,12 +3038,6 @@ "node": ">=8" } }, - "node_modules/itty-time": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/itty-time/-/itty-time-1.0.6.tgz", - "integrity": "sha512-+P8IZaLLBtFv8hCkIjcymZOp4UJ+xW6bSlQsXGqrkmJh7vSiMFSlNne0mCYagEE0N7HDNR5jJBRxwN0oYv61Rw==", - "dev": true - }, "node_modules/jest": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest/-/jest-29.7.0.tgz", @@ -3954,9 +3894,9 @@ } }, "node_modules/miniflare": { - "version": "3.20241022.0", - "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-3.20241022.0.tgz", - "integrity": "sha512-x9Fbq1Hmz1f0osIT9Qmj78iX4UpCP2EqlZnA/tzj/3+I49vc3Kq0fNqSSKplcdf6HlCHdL3fOBicmreQF4BUUQ==", + "version": "3.20240909.5", + "resolved": "https://registry.npmjs.org/miniflare/-/miniflare-3.20240909.5.tgz", + "integrity": "sha512-3Am3D9LGDljEKWnylSy6hFg3LFnNCo9DlWqZFcL7QkuIhQwN6Sqz1d6xQCkgft7FVXnykG6VNpz0NrjdW+mBjg==", "dev": true, "dependencies": { "@cspotcode/source-map-support": "0.8.1", @@ -3967,7 +3907,7 @@ "glob-to-regexp": "^0.4.1", "stoppable": "^1.1.0", "undici": "^5.28.4", - "workerd": "1.20241022.0", + "workerd": "1.20240909.0", "ws": "^8.17.1", "youch": "^3.2.2", "zod": "^3.22.3" @@ -4039,41 +3979,6 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, - "node_modules/node-domexception": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", - "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "github", - "url": "https://paypal.me/jimmywarting" - } - ], - "engines": { - "node": ">=10.5.0" - } - }, - "node_modules/node-fetch": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", - "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", - "dependencies": { - "data-uri-to-buffer": "^4.0.0", - "fetch-blob": "^3.1.4", - "formdata-polyfill": "^4.0.10" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/node-fetch" - } - }, "node_modules/node-forge": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", @@ -4951,9 +4856,9 @@ }, "node_modules/unenv": { "name": "unenv-nightly", - "version": "2.0.0-20241024-111401-d4156ac", - "resolved": "https://registry.npmjs.org/unenv-nightly/-/unenv-nightly-2.0.0-20241024-111401-d4156ac.tgz", - "integrity": "sha512-xJO1hfY+Te+/XnfCYrCbFbRcgu6XEODND1s5wnVbaBCkuQX7JXF7fHEXPrukFE2j8EOH848P8QN19VO47XN8hw==", + "version": "2.0.0-20240919-125358-9a64854", + "resolved": "https://registry.npmjs.org/unenv-nightly/-/unenv-nightly-2.0.0-20240919-125358-9a64854.tgz", + "integrity": "sha512-XjsgUTrTHR7iw+k/SRTNjh6EQgwpC9voygnoCJo5kh4hKqsSDHUW84MhL9EsHTNfLctvVBHaSw8e2k3R2fKXsQ==", "dev": true, "dependencies": { "defu": "^6.1.4", @@ -5034,14 +4939,6 @@ "makeerror": "1.0.12" } }, - "node_modules/web-streams-polyfill": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", - "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", - "engines": { - "node": ">= 8" - } - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -5058,9 +4955,9 @@ } }, "node_modules/workerd": { - "version": "1.20241022.0", - "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20241022.0.tgz", - "integrity": "sha512-jyGXsgO9DRcJyx6Ovv7gUyDPc3UYC2i/E0p9GFUg6GUzpldw4Y93y9kOmdfsOnKZ3+lY53veSiUniiBPE6Q2NQ==", + "version": "1.20240909.0", + "resolved": "https://registry.npmjs.org/workerd/-/workerd-1.20240909.0.tgz", + "integrity": "sha512-NwuYh/Fgr/MK0H+Ht687sHl/f8tumwT5CWzYR0MZMHri8m3CIYu2IaY4tBFWoKE/tOU1Z5XjEXECa9zXY4+lwg==", "dev": true, "hasInstallScript": true, "bin": { @@ -5070,37 +4967,35 @@ "node": ">=16" }, "optionalDependencies": { - "@cloudflare/workerd-darwin-64": "1.20241022.0", - "@cloudflare/workerd-darwin-arm64": "1.20241022.0", - "@cloudflare/workerd-linux-64": "1.20241022.0", - "@cloudflare/workerd-linux-arm64": "1.20241022.0", - "@cloudflare/workerd-windows-64": "1.20241022.0" + "@cloudflare/workerd-darwin-64": "1.20240909.0", + "@cloudflare/workerd-darwin-arm64": "1.20240909.0", + "@cloudflare/workerd-linux-64": "1.20240909.0", + "@cloudflare/workerd-linux-arm64": "1.20240909.0", + "@cloudflare/workerd-windows-64": "1.20240909.0" } }, "node_modules/wrangler": { - "version": "3.85.0", - "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-3.85.0.tgz", - "integrity": "sha512-r5YCWUaF4ApLnloNE6jHHgRYdFzYHoajTlC1tns42UzQ2Ls63VAqD3b0cxOqzDUfmlSb3skpmu0B0Ssi3QWPAg==", + "version": "3.78.9", + "resolved": "https://registry.npmjs.org/wrangler/-/wrangler-3.78.9.tgz", + "integrity": "sha512-4Z+KBai+xVU59EN8eyDyRXh+f0om3zKwIf2x9YZa9NCuw3bLF77n7wSoghjInTTYfPrKhsZqkPwlcDfVt/yK7g==", "dev": true, "dependencies": { "@cloudflare/kv-asset-handler": "0.3.4", - "@cloudflare/workers-shared": "0.7.0", + "@cloudflare/workers-shared": "0.5.4", "@esbuild-plugins/node-globals-polyfill": "^0.2.3", "@esbuild-plugins/node-modules-polyfill": "^0.2.2", "blake3-wasm": "^2.1.5", "chokidar": "^3.5.3", - "date-fns": "^4.1.0", "esbuild": "0.17.19", - "itty-time": "^1.0.6", - "miniflare": "3.20241022.0", + "miniflare": "3.20240909.5", "nanoid": "^3.3.3", "path-to-regexp": "^6.3.0", "resolve": "^1.22.8", "resolve.exports": "^2.0.2", "selfsigned": "^2.0.1", "source-map": "^0.6.1", - "unenv": "npm:unenv-nightly@2.0.0-20241024-111401-d4156ac", - "workerd": "1.20241022.0", + "unenv": "npm:unenv-nightly@2.0.0-20240919-125358-9a64854", + "workerd": "1.20240909.0", "xxhash-wasm": "^1.0.1" }, "bin": { @@ -5114,7 +5009,7 @@ "fsevents": "~2.3.2" }, "peerDependencies": { - "@cloudflare/workers-types": "^4.20241022.0" + "@cloudflare/workers-types": "^4.20240909.0" }, "peerDependenciesMeta": { "@cloudflare/workers-types": { @@ -5240,12 +5135,12 @@ } }, "node_modules/youch": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/youch/-/youch-3.3.4.tgz", - "integrity": "sha512-UeVBXie8cA35DS6+nBkls68xaBBXCye0CNznrhszZjTbRVnJKQuNsyLKBTTL4ln1o1rh2PKtv35twV7irj5SEg==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/youch/-/youch-3.3.3.tgz", + "integrity": "sha512-qSFXUk3UZBLfggAW3dJKg0BMblG5biqSF8M34E06o5CSsZtH92u9Hqmj2RzGiHDi64fhe83+4tENFP2DB6t6ZA==", "dev": true, "dependencies": { - "cookie": "^0.7.1", + "cookie": "^0.5.0", "mustache": "^4.2.0", "stacktracey": "^2.1.8" } diff --git a/ecosystem-tests/cloudflare-worker/package.json b/ecosystem-tests/cloudflare-worker/package.json index 3034e97f7..bec1aab03 100644 --- a/ecosystem-tests/cloudflare-worker/package.json +++ b/ecosystem-tests/cloudflare-worker/package.json @@ -17,9 +17,6 @@ "start-server-and-test": "^2.0.0", "ts-jest": "^29.1.0", "typescript": "5.0.4", - "wrangler": "^3.85.0" - }, - "dependencies": { - "node-fetch": "^3.3.1" + "wrangler": "^3.74.0" } } diff --git a/ecosystem-tests/cloudflare-worker/tests/test.js b/ecosystem-tests/cloudflare-worker/tests/test.js index 3a1ca3ea1..69981a0bb 100644 --- a/ecosystem-tests/cloudflare-worker/tests/test.js +++ b/ecosystem-tests/cloudflare-worker/tests/test.js @@ -1,5 +1,3 @@ -import fetch from 'node-fetch'; - it( 'works', async () => { diff --git a/ecosystem-tests/cloudflare-worker/tsconfig.check.json b/ecosystem-tests/cloudflare-worker/tsconfig.check.json index 22d6f227b..d1b622447 100644 --- a/ecosystem-tests/cloudflare-worker/tsconfig.check.json +++ b/ecosystem-tests/cloudflare-worker/tsconfig.check.json @@ -1,8 +1,5 @@ { "extends": "./tsconfig.json", "include": ["src"], - "exclude": ["tests", "jest.config.cjs"], - "compilerOptions": { - "skipLibCheck": false - } + "exclude": ["tests", "jest.config.cjs"] } diff --git a/ecosystem-tests/deno/deno.jsonc b/ecosystem-tests/deno/deno.jsonc index 46d7ee486..7de05f2ba 100644 --- a/ecosystem-tests/deno/deno.jsonc +++ b/ecosystem-tests/deno/deno.jsonc @@ -1,10 +1,11 @@ { "tasks": { "install": "deno install --node-modules-dir main_test.ts -f", - "test": "deno test --allow-env --allow-net --allow-read --node-modules-dir --unstable-sloppy-imports --no-check" + "check": "deno lint && deno check main_test.ts", + "test": "deno test --allow-env --allow-net --allow-read --node-modules-dir" }, "imports": { - "openai": "../../dist-deno/index.ts", - "openai/": "../../dist-deno/" + "openai": "../../deno/mod.ts", + "openai/": "../../deno/" } } diff --git a/ecosystem-tests/deno/package-lock.json b/ecosystem-tests/deno/package-lock.json deleted file mode 100644 index 99ead654a..000000000 --- a/ecosystem-tests/deno/package-lock.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "name": "deno", - "lockfileVersion": 3, - "requires": true, - "packages": { - "node_modules/.deno/asynckit@0.4.0/node_modules/asynckit": { - "version": "0.4.0", - "extraneous": true, - "license": "MIT", - "devDependencies": { - "browserify": "^13.0.0", - "browserify-istanbul": "^2.0.0", - "coveralls": "^2.11.9", - "eslint": "^2.9.0", - "istanbul": "^0.4.3", - "obake": "^0.1.2", - "phantomjs-prebuilt": "^2.1.7", - "pre-commit": "^1.1.3", - "reamde": "^1.1.0", - "rimraf": "^2.5.2", - "size-table": "^0.2.0", - "tap-spec": "^4.1.1", - "tape": "^4.5.1" - } - }, - "node_modules/.deno/axios@0.26.1": {}, - "node_modules/.deno/combined-stream@1.0.8": {}, - "node_modules/.deno/delayed-stream@1.0.0/node_modules/delayed-stream": { - "version": "1.0.0", - "extraneous": true, - "license": "MIT", - "devDependencies": { - "fake": "0.2.0", - "far": "0.0.1" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/.deno/follow-redirects@1.15.2/node_modules/follow-redirects": { - "version": "1.15.2", - "extraneous": true, - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "license": "MIT", - "devDependencies": { - "concat-stream": "^2.0.0", - "eslint": "^5.16.0", - "express": "^4.16.4", - "lolex": "^3.1.0", - "mocha": "^6.0.2", - "nyc": "^14.1.1" - }, - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, - "node_modules/.deno/form-data@4.0.0": {}, - "node_modules/.deno/mime-db@1.52.0/node_modules/mime-db": { - "version": "1.52.0", - "extraneous": true, - "license": "MIT", - "devDependencies": { - "bluebird": "3.7.2", - "co": "4.6.0", - "cogent": "1.0.1", - "csv-parse": "4.16.3", - "eslint": "7.32.0", - "eslint-config-standard": "15.0.1", - "eslint-plugin-import": "2.25.4", - "eslint-plugin-markdown": "2.2.1", - "eslint-plugin-node": "11.1.0", - "eslint-plugin-promise": "5.1.1", - "eslint-plugin-standard": "4.1.0", - "gnode": "0.1.2", - "media-typer": "1.1.0", - "mocha": "9.2.1", - "nyc": "15.1.0", - "raw-body": "2.5.0", - "stream-to-array": "2.3.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/.deno/mime-types@2.1.35": {}, - "node_modules/.deno/openai@3.3.0": {} - } -} diff --git a/ecosystem-tests/node-js/package-lock.json b/ecosystem-tests/node-js/package-lock.json index bb59ccb92..064116bdb 100644 --- a/ecosystem-tests/node-js/package-lock.json +++ b/ecosystem-tests/node-js/package-lock.json @@ -5,240 +5,9 @@ "requires": true, "packages": { "": { - "name": "foo", + "name": "node-js", "version": "1.0.0", - "license": "ISC", - "dependencies": { - "openai": "^4.40.1" - } - }, - "node_modules/@types/node": { - "version": "18.19.31", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.31.tgz", - "integrity": "sha512-ArgCD39YpyyrtFKIqMDvjz79jto5fcI/SVUs2HwB+f0dAzq68yqOdyaSivLiLugSziTpNXLQrVb7RZFmdZzbhA==", - "dependencies": { - "undici-types": "~5.26.4" - } - }, - "node_modules/@types/node-fetch": { - "version": "2.6.11", - "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.11.tgz", - "integrity": "sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==", - "dependencies": { - "@types/node": "*", - "form-data": "^4.0.0" - } - }, - "node_modules/abort-controller": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", - "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", - "dependencies": { - "event-target-shim": "^5.0.0" - }, - "engines": { - "node": ">=6.5" - } - }, - "node_modules/agentkeepalive": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz", - "integrity": "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==", - "dependencies": { - "humanize-ms": "^1.2.1" - }, - "engines": { - "node": ">= 8.0.0" - } - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/event-target-shim": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", - "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", - "engines": { - "node": ">=6" - } - }, - "node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/form-data-encoder": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.2.tgz", - "integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==" - }, - "node_modules/formdata-node": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz", - "integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==", - "dependencies": { - "node-domexception": "1.0.0", - "web-streams-polyfill": "4.0.0-beta.3" - }, - "engines": { - "node": ">= 12.20" - } - }, - "node_modules/formdata-node/node_modules/web-streams-polyfill": { - "version": "4.0.0-beta.3", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz", - "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==", - "engines": { - "node": ">= 14" - } - }, - "node_modules/humanize-ms": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", - "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", - "dependencies": { - "ms": "^2.0.0" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, - "node_modules/node-domexception": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", - "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "github", - "url": "https://paypal.me/jimmywarting" - } - ], - "engines": { - "node": ">=10.5.0" - } - }, - "node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/openai": { - "version": "4.40.1", - "resolved": "https://registry.npmjs.org/openai/-/openai-4.40.1.tgz", - "integrity": "sha512-mS7LerF4fY1/we0aKGGwIWtosTJFLKuNbBWMBR/G1TAZUHoktAdod0dqIrlQvSD39uS6jNEEbT7jRsXmzfEPBw==", - "dependencies": { - "@types/node": "^18.11.18", - "@types/node-fetch": "^2.6.4", - "abort-controller": "^3.0.0", - "agentkeepalive": "^4.2.1", - "form-data-encoder": "1.7.2", - "formdata-node": "^4.3.2", - "node-fetch": "^2.6.7", - "web-streams-polyfill": "^3.2.1" - }, - "bin": { - "openai": "bin/cli" - } - }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" - }, - "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" - }, - "node_modules/web-streams-polyfill": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", - "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", - "engines": { - "node": ">= 8" - } - }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } + "license": "ISC" } } } diff --git a/ecosystem-tests/node-js/package.json b/ecosystem-tests/node-js/package.json index 63f858014..eeb432712 100644 --- a/ecosystem-tests/node-js/package.json +++ b/ecosystem-tests/node-js/package.json @@ -7,8 +7,5 @@ "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", - "license": "ISC", - "dependencies": { - "openai": "^4.40.1" - } + "license": "ISC" } diff --git a/ecosystem-tests/node-js/test.js b/ecosystem-tests/node-js/test.js index e2a26f856..7f9f21736 100644 --- a/ecosystem-tests/node-js/test.js +++ b/ecosystem-tests/node-js/test.js @@ -1,35 +1,8 @@ +const openaiKey = "a valid OpenAI key" const OpenAI = require('openai'); -const openai = new OpenAI(); +console.log(OpenAI) -function assertEqual(actual, expected) { - if (actual === expected) { - return; - } - - console.error('expected', expected); - console.error('actual ', actual); - throw new Error('expected values to be equal'); -} - -async function main() { - const completion = await openai.chat.completions.create({ - model: 'gpt-4', - messages: [{ role: 'user', content: 'Say this is a test' }], - }); - if (!completion.choices[0].message.content) { - console.dir(completion, { depth: 4 }); - throw new Error('no response content!'); - } - - assertEqual( - decodeURIComponent(openai.stringifyQuery({ foo: { nested: { a: true, b: 'foo' } } })), - 'foo[nested][a]=true&foo[nested][b]=foo', - ); - assertEqual( - decodeURIComponent(openai.stringifyQuery({ foo: { nested: { a: ['hello', 'world'] } } })), - 'foo[nested][a][]=hello&foo[nested][a][]=world', - ); -} - -main(); +const openai = new OpenAI({ + apiKey: openaiKey, +}); diff --git a/ecosystem-tests/node-ts-cjs-auto/moduleResolution/nodenext/type-tests.ts b/ecosystem-tests/node-ts-cjs-auto/moduleResolution/nodenext/type-tests.ts index c47ddc2a5..e70cad642 100644 --- a/ecosystem-tests/node-ts-cjs-auto/moduleResolution/nodenext/type-tests.ts +++ b/ecosystem-tests/node-ts-cjs-auto/moduleResolution/nodenext/type-tests.ts @@ -1,5 +1,6 @@ -import * as shims from 'openai/_shims/index'; +import OpenAI from 'openai'; -function typeTests(x: shims.Request) { - const url: string = x.url; +async function typeTests(client: OpenAI) { + const response = await client.chat.completions.create({ model: 'gpt-4o', messages: [] }).asResponse(); + const url: string = response.url; } diff --git a/ecosystem-tests/node-ts-cjs-auto/package-lock.json b/ecosystem-tests/node-ts-cjs-auto/package-lock.json index c3880beb2..68233e13b 100644 --- a/ecosystem-tests/node-ts-cjs-auto/package-lock.json +++ b/ecosystem-tests/node-ts-cjs-auto/package-lock.json @@ -9,12 +9,10 @@ "version": "0.0.1", "dependencies": { "formdata-node": "^4.4.1", - "node-fetch": "^2.6.1", "tsconfig-paths": "^4.0.0" }, "devDependencies": { "@types/node": "^20.4.2", - "@types/node-fetch": "^2.6.1", "@types/ws": "^8.5.4", "fastest-levenshtein": "^1.0.16", "jest": "^28.1.3", @@ -1101,16 +1099,6 @@ "undici-types": "~5.26.4" } }, - "node_modules/@types/node-fetch": { - "version": "2.6.11", - "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.11.tgz", - "integrity": "sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==", - "dev": true, - "dependencies": { - "@types/node": "*", - "form-data": "^4.0.0" - } - }, "node_modules/@types/prettier": { "version": "2.7.3", "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.3.tgz", @@ -1208,12 +1196,6 @@ "sprintf-js": "~1.0.2" } }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true - }, "node_modules/babel-jest": { "version": "28.1.3", "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-28.1.3.tgz", @@ -1524,18 +1506,6 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -1594,15 +1564,6 @@ "node": ">=0.10.0" } }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/detect-newline": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", @@ -1782,20 +1743,6 @@ "node": ">=8" } }, - "node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dev": true, - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/formdata-node": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz", @@ -2886,27 +2833,6 @@ "node": ">=8.6" } }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/mimic-fn": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", @@ -2966,25 +2892,6 @@ "node": ">=10.5.0" } }, - "node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -3551,11 +3458,6 @@ "node": ">=8.0" } }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" - }, "node_modules/ts-jest": { "version": "28.0.8", "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-28.0.8.tgz", @@ -3754,20 +3656,6 @@ "node": ">= 14" } }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", diff --git a/ecosystem-tests/node-ts-cjs-auto/package.json b/ecosystem-tests/node-ts-cjs-auto/package.json index 17e4ae9e6..44f55d778 100644 --- a/ecosystem-tests/node-ts-cjs-auto/package.json +++ b/ecosystem-tests/node-ts-cjs-auto/package.json @@ -9,12 +9,10 @@ }, "dependencies": { "formdata-node": "^4.4.1", - "node-fetch": "^2.6.1", "tsconfig-paths": "^4.0.0" }, "devDependencies": { "@types/node": "^20.4.2", - "@types/node-fetch": "^2.6.1", "@types/ws": "^8.5.4", "fastest-levenshtein": "^1.0.16", "jest": "^28.1.3", diff --git a/ecosystem-tests/node-ts-cjs-auto/tests/shims.ts b/ecosystem-tests/node-ts-cjs-auto/tests/shims.ts deleted file mode 100644 index d34211578..000000000 --- a/ecosystem-tests/node-ts-cjs-auto/tests/shims.ts +++ /dev/null @@ -1,7 +0,0 @@ -import * as shims from 'openai/_shims/index'; -import * as fd from 'formdata-node'; - -test('openai/shims/node', () => { - expect(shims.kind).toEqual('node'); - expect(shims.File).toBe(fd.File); -}); diff --git a/ecosystem-tests/node-ts-cjs-auto/tests/test.ts b/ecosystem-tests/node-ts-cjs-auto/tests/test.ts index 203afba5a..ea6913ef6 100644 --- a/ecosystem-tests/node-ts-cjs-auto/tests/test.ts +++ b/ecosystem-tests/node-ts-cjs-auto/tests/test.ts @@ -1,9 +1,9 @@ import OpenAI, { APIUserAbortError, toFile } from 'openai'; import { TranscriptionCreateParams } from 'openai/resources/audio/transcriptions'; -import fetch from 'node-fetch'; import { File as FormDataFile, Blob as FormDataBlob } from 'formdata-node'; import * as fs from 'fs'; import { distance } from 'fastest-levenshtein'; +import { File } from 'node:buffer'; const url = 'https://audio-samples.github.io/samples/mp3/blizzard_biased/sample-1.mp3'; const filename = 'sample-1.mp3'; @@ -154,30 +154,24 @@ it(`aborting ChatCompletionStream works`, async function () { expect(contents.length).toBeGreaterThan(0); }); -it('handles formdata-node File', async function () { +it('handles builtinFile', async function () { const file = await fetch(url) .then((x) => x.arrayBuffer()) - .then((x) => new FormDataFile([x], filename)); - - const params: TranscriptionCreateParams = { file, model }; + .then( + (x) => + new File( + [ + // @ts-ignore array buffer can't be passed to File at the type-level + x, + ], + filename, + ), + ); - const result = await client.audio.transcriptions.create(params); + const result = await client.audio.transcriptions.create({ file, model }); expect(result.text).toBeSimilarTo(correctAnswer, 12); }); -// @ts-ignore avoid DOM lib for testing purposes -if (typeof File !== 'undefined') { - it('handles builtinFile', async function () { - const file = await fetch(url) - .then((x) => x.arrayBuffer()) - // @ts-ignore avoid DOM lib for testing purposes - .then((x) => new File([x], filename)); - - const result = await client.audio.transcriptions.create({ file, model }); - expect(result.text).toBeSimilarTo(correctAnswer, 12); - }); -} - it('handles Response', async function () { const file = await fetch(url); @@ -198,26 +192,15 @@ const fineTune = `{"prompt": "", "completion": " { it('handles form-data Blob', async function () { const result = await client.files.create({ - file: await toFile( - new FormDataBlob([ - // @ts-ignore avoid DOM lib for testing purposes - new TextEncoder().encode(fineTune), - ]), - 'finetune.jsonl', - ), + file: await toFile(new FormDataBlob([new TextEncoder().encode(fineTune)]), 'finetune.jsonl'), purpose: 'fine-tune', }); expect(result.filename).toEqual('finetune.jsonl'); }); - // @ts-ignore avoid DOM lib for testing purposes if (typeof Blob !== 'undefined') { it('handles builtin Blob', async function () { const result = await client.files.create({ - file: await toFile( - // @ts-ignore avoid DOM lib for testing purposes - new Blob([new TextEncoder().encode(fineTune)]), - 'finetune.jsonl', - ), + file: await toFile(new Blob([new TextEncoder().encode(fineTune)]), 'finetune.jsonl'), purpose: 'fine-tune', }); expect(result.filename).toEqual('finetune.jsonl'); @@ -225,44 +208,35 @@ describe('toFile', () => { } it('handles Uint8Array', async function () { const result = await client.files.create({ - file: await toFile( - // @ts-ignore avoid DOM lib for testing purposes - new TextEncoder().encode(fineTune), - 'finetune.jsonl', - ), + file: await toFile(new TextEncoder().encode(fineTune), 'finetune.jsonl'), purpose: 'fine-tune', }); expect(result.filename).toEqual('finetune.jsonl'); }); it('handles ArrayBuffer', async function () { const result = await client.files.create({ - file: await toFile( - // @ts-ignore avoid DOM lib for testing purposes - new TextEncoder().encode(fineTune).buffer, - 'finetune.jsonl', - ), + file: await toFile(new TextEncoder().encode(fineTune).buffer, 'finetune.jsonl'), purpose: 'fine-tune', }); expect(result.filename).toEqual('finetune.jsonl'); }); it('handles DataView', async function () { const result = await client.files.create({ - file: await toFile( - // @ts-ignore avoid DOM lib for testing purposes - new DataView(new TextEncoder().encode(fineTune).buffer), - 'finetune.jsonl', - ), + file: await toFile(new DataView(new TextEncoder().encode(fineTune).buffer), 'finetune.jsonl'), purpose: 'fine-tune', }); expect(result.filename).toEqual('finetune.jsonl'); }); -}); + it('handles formdata-node File', async function () { + const file = await fetch(url) + .then((x) => x.arrayBuffer()) + .then((x) => toFile(new FormDataFile([x], filename))); -test('query strings', () => { - expect( - decodeURIComponent((client as any).stringifyQuery({ foo: { nested: { a: true, b: 'foo' } } })), - ).toEqual('foo[nested][a]=true&foo[nested][b]=foo'); - expect( - decodeURIComponent((client as any).stringifyQuery({ foo: { nested: { a: ['hello', 'world'] } } })), - ).toEqual('foo[nested][a][]=hello&foo[nested][a][]=world'); + expect(file.name).toEqual(filename); + + const params: TranscriptionCreateParams = { file, model }; + + const result = await client.audio.transcriptions.create(params); + expect(result.text).toBeSimilarTo(correctAnswer, 12); + }); }); diff --git a/ecosystem-tests/node-ts-cjs-web/package-lock.json b/ecosystem-tests/node-ts-cjs-web/package-lock.json index ff6fb3bac..48980c2f8 100644 --- a/ecosystem-tests/node-ts-cjs-web/package-lock.json +++ b/ecosystem-tests/node-ts-cjs-web/package-lock.json @@ -9,21 +9,15 @@ "version": "0.0.1", "dependencies": { "formdata-node": "^4.4.1", - "node-fetch": "^2.6.1", "tsconfig-paths": "^4.0.0" }, "devDependencies": { - "@types/node": "^17.0.9", - "@types/node-fetch": "^2.6.1", + "@types/node": "^18.0.0", "fastest-levenshtein": "^1.0.16", - "formdata-polyfill": "^4.0.10", "jest": "^29.5.0", - "jest-environment-jsdom": "^29.7.0", - "text-encoding-polyfill": "^0.6.7", + "jest-fixed-jsdom": "^0.0.9", "ts-jest": "^29.1.0", - "typescript": "4.7.4", - "web-streams-polyfill": "^3.2.1", - "whatwg-fetch": "^3.6.19" + "typescript": "4.7.4" } }, "node_modules/@ampproject/remapping": { @@ -1047,6 +1041,7 @@ "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", "dev": true, + "peer": true, "engines": { "node": ">= 10" } @@ -1130,6 +1125,7 @@ "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-20.0.1.tgz", "integrity": "sha512-d0r18sZPmMQr1eG35u12FZfhIXNrnsPU/g5wvRKCUf/tOGilKKwYMYGqh33BNR6ba+2gkHw1EUiHoN3mn7E5IQ==", "dev": true, + "peer": true, "dependencies": { "@types/node": "*", "@types/tough-cookie": "*", @@ -1137,19 +1133,13 @@ } }, "node_modules/@types/node": { - "version": "17.0.45", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz", - "integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==", - "dev": true - }, - "node_modules/@types/node-fetch": { - "version": "2.6.11", - "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.11.tgz", - "integrity": "sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==", + "version": "18.19.64", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.64.tgz", + "integrity": "sha512-955mDqvO2vFf/oL7V3WiUtiz+BugyX8uVbaT2H8oj3+8dRyH2FLiNdowe7eNqRM7IOIZvzDH76EoAT+gwm6aIQ==", "dev": true, + "license": "MIT", "dependencies": { - "@types/node": "*", - "form-data": "^4.0.0" + "undici-types": "~5.26.4" } }, "node_modules/@types/stack-utils": { @@ -1162,7 +1152,8 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.3.tgz", "integrity": "sha512-THo502dA5PzG/sfQH+42Lw3fvmYkceefOspdCwpHRul8ik2Jv1K8I5OZz1AT3/rs46kwgMCe9bSBmDLYkkOMGg==", - "dev": true + "dev": true, + "peer": true }, "node_modules/@types/yargs": { "version": "17.0.24", @@ -1183,13 +1174,15 @@ "version": "2.0.6", "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", - "dev": true + "dev": true, + "peer": true }, "node_modules/acorn": { "version": "8.10.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", "dev": true, + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -1202,6 +1195,7 @@ "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-7.0.1.tgz", "integrity": "sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==", "dev": true, + "peer": true, "dependencies": { "acorn": "^8.1.0", "acorn-walk": "^8.0.2" @@ -1212,6 +1206,7 @@ "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", "dev": true, + "peer": true, "engines": { "node": ">=0.4.0" } @@ -1221,6 +1216,7 @@ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", "dev": true, + "peer": true, "dependencies": { "debug": "4" }, @@ -1293,7 +1289,8 @@ "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true + "dev": true, + "peer": true }, "node_modules/babel-jest": { "version": "29.7.0", @@ -1626,6 +1623,7 @@ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "dev": true, + "peer": true, "dependencies": { "delayed-stream": "~1.0.0" }, @@ -1684,13 +1682,15 @@ "version": "0.5.0", "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz", "integrity": "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==", - "dev": true + "dev": true, + "peer": true }, "node_modules/cssstyle": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", "dev": true, + "peer": true, "dependencies": { "cssom": "~0.3.6" }, @@ -1702,13 +1702,15 @@ "version": "0.3.8", "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", - "dev": true + "dev": true, + "peer": true }, "node_modules/data-urls": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.2.tgz", "integrity": "sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==", "dev": true, + "peer": true, "dependencies": { "abab": "^2.0.6", "whatwg-mimetype": "^3.0.0", @@ -1723,6 +1725,7 @@ "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", "dev": true, + "peer": true, "dependencies": { "punycode": "^2.1.1" }, @@ -1735,6 +1738,7 @@ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", "dev": true, + "peer": true, "engines": { "node": ">=12" } @@ -1744,6 +1748,7 @@ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", "dev": true, + "peer": true, "dependencies": { "tr46": "^3.0.0", "webidl-conversions": "^7.0.0" @@ -1773,7 +1778,8 @@ "version": "10.4.3", "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", - "dev": true + "dev": true, + "peer": true }, "node_modules/dedent": { "version": "1.5.1", @@ -1803,6 +1809,7 @@ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", "dev": true, + "peer": true, "engines": { "node": ">=0.4.0" } @@ -1830,6 +1837,7 @@ "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==", "dev": true, + "peer": true, "dependencies": { "webidl-conversions": "^7.0.0" }, @@ -1842,6 +1850,7 @@ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", "dev": true, + "peer": true, "engines": { "node": ">=12" } @@ -1875,6 +1884,7 @@ "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", "dev": true, + "peer": true, "engines": { "node": ">=0.12" }, @@ -1914,6 +1924,7 @@ "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", "dev": true, + "peer": true, "dependencies": { "esprima": "^4.0.1", "estraverse": "^5.2.0", @@ -1948,6 +1959,7 @@ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, + "peer": true, "engines": { "node": ">=4.0" } @@ -1957,6 +1969,7 @@ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true, + "peer": true, "engines": { "node": ">=0.10.0" } @@ -2033,29 +2046,6 @@ "bser": "2.1.1" } }, - "node_modules/fetch-blob": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", - "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "paypal", - "url": "https://paypal.me/jimmywarting" - } - ], - "dependencies": { - "node-domexception": "^1.0.0", - "web-streams-polyfill": "^3.0.3" - }, - "engines": { - "node": "^12.20 || >= 14.13" - } - }, "node_modules/fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -2086,6 +2076,7 @@ "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", "dev": true, + "peer": true, "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -2115,18 +2106,6 @@ "node": ">= 14" } }, - "node_modules/formdata-polyfill": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", - "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", - "dev": true, - "dependencies": { - "fetch-blob": "^3.1.2" - }, - "engines": { - "node": ">=12.20.0" - } - }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -2256,6 +2235,7 @@ "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", "dev": true, + "peer": true, "dependencies": { "whatwg-encoding": "^2.0.0" }, @@ -2274,6 +2254,7 @@ "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", "dev": true, + "peer": true, "dependencies": { "@tootallnate/once": "2", "agent-base": "6", @@ -2288,6 +2269,7 @@ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", "dev": true, + "peer": true, "dependencies": { "agent-base": "6", "debug": "4" @@ -2310,6 +2292,7 @@ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "dev": true, + "peer": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" }, @@ -2410,7 +2393,8 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", - "dev": true + "dev": true, + "peer": true }, "node_modules/is-stream": { "version": "2.0.1", @@ -2726,6 +2710,7 @@ "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-29.7.0.tgz", "integrity": "sha512-k9iQbsf9OyOfdzWH8HDmrRT0gSIcX+FLNW7IQq94tFX0gynPwqDTW0Ho6iMVNjGz/nb+l/vW3dWM2bbLLpkbXA==", "dev": true, + "peer": true, "dependencies": { "@jest/environment": "^29.7.0", "@jest/fake-timers": "^29.7.0", @@ -2765,6 +2750,19 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-fixed-jsdom": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/jest-fixed-jsdom/-/jest-fixed-jsdom-0.0.9.tgz", + "integrity": "sha512-KPfqh2+sn5q2B+7LZktwDcwhCpOpUSue8a1I+BcixWLOQoEVyAjAGfH+IYZGoxZsziNojoHGRTC8xRbB1wDD4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "jest-environment-jsdom": ">=28.0.0" + } + }, "node_modules/jest-get-type": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", @@ -3168,6 +3166,7 @@ "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-20.0.3.tgz", "integrity": "sha512-SYhBvTh89tTfCD/CRdSOm13mOBa42iTaTyfyEWBdKcGdPxPtLFBXuHR8XHb33YNYaP+lLbmSvBTsnoesCNJEsQ==", "dev": true, + "peer": true, "dependencies": { "abab": "^2.0.6", "acorn": "^8.8.1", @@ -3213,6 +3212,7 @@ "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", "dev": true, + "peer": true, "dependencies": { "punycode": "^2.1.1" }, @@ -3225,6 +3225,7 @@ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", "dev": true, + "peer": true, "engines": { "node": ">=12" } @@ -3234,6 +3235,7 @@ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", "dev": true, + "peer": true, "dependencies": { "tr46": "^3.0.0", "webidl-conversions": "^7.0.0" @@ -3409,6 +3411,7 @@ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "dev": true, + "peer": true, "engines": { "node": ">= 0.6" } @@ -3418,6 +3421,7 @@ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dev": true, + "peer": true, "dependencies": { "mime-db": "1.52.0" }, @@ -3484,25 +3488,6 @@ "node": ">=10.5.0" } }, - "node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -3540,7 +3525,8 @@ "version": "2.2.7", "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.7.tgz", "integrity": "sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==", - "dev": true + "dev": true, + "peer": true }, "node_modules/once": { "version": "1.4.0", @@ -3640,6 +3626,7 @@ "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", "dev": true, + "peer": true, "dependencies": { "entities": "^4.4.0" }, @@ -3762,13 +3749,15 @@ "version": "1.9.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", - "dev": true + "dev": true, + "peer": true }, "node_modules/punycode": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", "dev": true, + "peer": true, "engines": { "node": ">=6" } @@ -3793,7 +3782,8 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", - "dev": true + "dev": true, + "peer": true }, "node_modules/react-is": { "version": "18.2.0", @@ -3814,7 +3804,8 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", - "dev": true + "dev": true, + "peer": true }, "node_modules/resolve": { "version": "1.22.8", @@ -3867,13 +3858,15 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true + "dev": true, + "peer": true }, "node_modules/saxes": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", "dev": true, + "peer": true, "dependencies": { "xmlchars": "^2.2.0" }, @@ -4066,7 +4059,8 @@ "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", - "dev": true + "dev": true, + "peer": true }, "node_modules/test-exclude": { "version": "6.0.0", @@ -4082,12 +4076,6 @@ "node": ">=8" } }, - "node_modules/text-encoding-polyfill": { - "version": "0.6.7", - "resolved": "https://registry.npmjs.org/text-encoding-polyfill/-/text-encoding-polyfill-0.6.7.tgz", - "integrity": "sha512-/DZ1XJqhbqRkCop6s9ZFu8JrFRwmVuHg4quIRm+ziFkR3N3ec6ck6yBvJ1GYeEQZhLVwRW0rZE+C3SSJpy0RTg==", - "dev": true - }, "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -4120,6 +4108,7 @@ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", "dev": true, + "peer": true, "dependencies": { "psl": "^1.1.33", "punycode": "^2.1.1", @@ -4130,11 +4119,6 @@ "node": ">=6" } }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" - }, "node_modules/ts-jest": { "version": "29.1.2", "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.1.2.tgz", @@ -4266,11 +4250,19 @@ "node": ">=4.2.0" } }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true, + "license": "MIT" + }, "node_modules/universalify": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", "dev": true, + "peer": true, "engines": { "node": ">= 4.0.0" } @@ -4310,6 +4302,7 @@ "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", "dev": true, + "peer": true, "dependencies": { "querystringify": "^2.1.1", "requires-port": "^1.0.0" @@ -4334,6 +4327,7 @@ "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz", "integrity": "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==", "dev": true, + "peer": true, "dependencies": { "xml-name-validator": "^4.0.0" }, @@ -4350,25 +4344,12 @@ "makeerror": "1.0.12" } }, - "node_modules/web-streams-polyfill": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", - "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" - }, "node_modules/whatwg-encoding": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", "dev": true, + "peer": true, "dependencies": { "iconv-lite": "0.6.3" }, @@ -4376,30 +4357,16 @@ "node": ">=12" } }, - "node_modules/whatwg-fetch": { - "version": "3.6.20", - "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz", - "integrity": "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==", - "dev": true - }, "node_modules/whatwg-mimetype": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", "dev": true, + "peer": true, "engines": { "node": ">=12" } }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -4456,6 +4423,7 @@ "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.1.tgz", "integrity": "sha512-4OOseMUq8AzRBI/7SLMUwO+FEDnguetSk7KMb1sHwvF2w2Wv5Hoj0nlifx8vtGsftE/jWHojPy8sMMzYLJ2G/A==", "dev": true, + "peer": true, "engines": { "node": ">=10.0.0" }, @@ -4477,6 +4445,7 @@ "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", "dev": true, + "peer": true, "engines": { "node": ">=12" } @@ -4485,7 +4454,8 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", - "dev": true + "dev": true, + "peer": true }, "node_modules/y18n": { "version": "5.0.8", diff --git a/ecosystem-tests/node-ts-cjs-web/package.json b/ecosystem-tests/node-ts-cjs-web/package.json index 8a50fcb43..6683953fd 100644 --- a/ecosystem-tests/node-ts-cjs-web/package.json +++ b/ecosystem-tests/node-ts-cjs-web/package.json @@ -9,20 +9,14 @@ }, "dependencies": { "formdata-node": "^4.4.1", - "node-fetch": "^2.6.1", "tsconfig-paths": "^4.0.0" }, "devDependencies": { - "@types/node": "^17.0.9", - "@types/node-fetch": "^2.6.1", + "jest-fixed-jsdom": "^0.0.9", + "@types/node": "^18.0.0", "fastest-levenshtein": "^1.0.16", - "formdata-polyfill": "^4.0.10", "jest": "^29.5.0", - "jest-environment-jsdom": "^29.7.0", - "text-encoding-polyfill": "^0.6.7", "ts-jest": "^29.1.0", - "typescript": "4.7.4", - "web-streams-polyfill": "^3.2.1", - "whatwg-fetch": "^3.6.19" + "typescript": "4.7.4" } } diff --git a/ecosystem-tests/node-ts-cjs-web/tests/shims.ts b/ecosystem-tests/node-ts-cjs-web/tests/shims.ts deleted file mode 100644 index 07279b9eb..000000000 --- a/ecosystem-tests/node-ts-cjs-web/tests/shims.ts +++ /dev/null @@ -1,11 +0,0 @@ -import 'openai/shims/web'; -import * as shims from 'openai/_shims/index'; - -function typeTests(x: shims.Request) { - const url: string = x.url; -} - -test('openai/shims/node', () => { - expect(shims.kind).toEqual('web'); - expect(shims.File).toBe(File); -}); diff --git a/ecosystem-tests/node-ts-cjs-web/tests/test-jsdom-unpolyfilled.ts b/ecosystem-tests/node-ts-cjs-web/tests/test-jsdom-unpolyfilled.ts deleted file mode 100644 index e536f3047..000000000 --- a/ecosystem-tests/node-ts-cjs-web/tests/test-jsdom-unpolyfilled.ts +++ /dev/null @@ -1,11 +0,0 @@ -/** - * @jest-environment jsdom - */ - -export {}; - -test('openai/shims/web throws if globals are missing', async () => { - await expect(() => import('openai/shims/web')).rejects.toThrow( - `this environment is missing the following Web Fetch API type: fetch is not defined. You may need to use polyfills`, - ); -}); diff --git a/ecosystem-tests/node-ts-cjs-web/tests/test-jsdom.ts b/ecosystem-tests/node-ts-cjs-web/tests/test-jsdom.ts index e7b6be07d..d156fcbfd 100644 --- a/ecosystem-tests/node-ts-cjs-web/tests/test-jsdom.ts +++ b/ecosystem-tests/node-ts-cjs-web/tests/test-jsdom.ts @@ -1,13 +1,9 @@ /** - * @jest-environment jsdom + * @jest-environment jest-fixed-jsdom */ -import 'whatwg-fetch'; -import 'openai/shims/web'; import OpenAI, { toFile } from 'openai'; import { distance } from 'fastest-levenshtein'; import { ChatCompletion } from 'openai/resources/chat/completions'; -// @ts-ignore -import { TextEncoder } from 'text-encoding-polyfill'; const url = 'https://audio-samples.github.io/samples/mp3/blizzard_biased/sample-1.mp3'; const filename = 'sample-1.mp3'; @@ -164,12 +160,3 @@ describe.skip('toFile', () => { expect(result.filename).toEqual('finetune.jsonl'); }); }); - -test('query strings', () => { - expect( - decodeURIComponent((client as any).stringifyQuery({ foo: { nested: { a: true, b: 'foo' } } })), - ).toEqual('foo[nested][a]=true&foo[nested][b]=foo'); - expect( - decodeURIComponent((client as any).stringifyQuery({ foo: { nested: { a: ['hello', 'world'] } } })), - ).toEqual('foo[nested][a][]=hello&foo[nested][a][]=world'); -}); diff --git a/ecosystem-tests/node-ts-cjs-web/tests/test-node.ts b/ecosystem-tests/node-ts-cjs-web/tests/test-node.ts index 668e65332..c357d7070 100644 --- a/ecosystem-tests/node-ts-cjs-web/tests/test-node.ts +++ b/ecosystem-tests/node-ts-cjs-web/tests/test-node.ts @@ -1,4 +1,3 @@ -import 'openai/shims/web'; import OpenAI, { toFile } from 'openai'; import { distance } from 'fastest-levenshtein'; import { ChatCompletion } from 'openai/resources/chat/completions'; @@ -103,6 +102,7 @@ if (typeof File !== 'undefined') { it('handles builtinFile', async function () { const file = await fetch(url) .then((x) => x.arrayBuffer()) + // @ts-ignore .then((x) => new File([x], filename)); const result = await client.audio.transcriptions.create({ file, model }); @@ -151,12 +151,3 @@ describe('toFile', () => { expect(result.filename).toEqual('finetune.jsonl'); }); }); - -test('query strings', () => { - expect( - decodeURIComponent((client as any).stringifyQuery({ foo: { nested: { a: true, b: 'foo' } } })), - ).toEqual('foo[nested][a]=true&foo[nested][b]=foo'); - expect( - decodeURIComponent((client as any).stringifyQuery({ foo: { nested: { a: ['hello', 'world'] } } })), - ).toEqual('foo[nested][a][]=hello&foo[nested][a][]=world'); -}); diff --git a/ecosystem-tests/node-ts-cjs-web/types-test.ts b/ecosystem-tests/node-ts-cjs-web/types-test.ts new file mode 100644 index 000000000..bff3349c5 --- /dev/null +++ b/ecosystem-tests/node-ts-cjs-web/types-test.ts @@ -0,0 +1,8 @@ +import OpenAI from 'openai'; + +async function typeTests(client: OpenAI) { + const response = await client.chat.completions.create({ model: 'gpt-4o', messages: [] }).asResponse(); + const url: string = response.url; +} + +export {}; diff --git a/ecosystem-tests/node-ts-cjs/package-lock.json b/ecosystem-tests/node-ts-cjs/package-lock.json index 2f5374e35..dcbda28e4 100644 --- a/ecosystem-tests/node-ts-cjs/package-lock.json +++ b/ecosystem-tests/node-ts-cjs/package-lock.json @@ -9,19 +9,17 @@ "version": "0.0.1", "dependencies": { "formdata-node": "^4.4.1", - "node-fetch": "^2.6.1", - "tsconfig-paths": "^4.0.0" + "tsconfig-paths": "^4.0.0", + "typescript": "^5.7.3", + "undici": "^7.2.0" }, "devDependencies": { - "@types/node": "20.4.2", - "@types/node-fetch": "^2.6.1", + "@types/node": "^20.14.8", "@types/ws": "^8.5.4", "fastest-levenshtein": "^1.0.16", "jest": "^29.5.0", - "jest-environment-jsdom": "^29.7.0", - "text-encoding-polyfill": "^0.6.7", - "ts-jest": "^29.1.0", - "typescript": "4.7.4" + "jest-fixed-jsdom": "^0.0.9", + "ts-jest": "^29.1.0" } }, "node_modules/@ampproject/remapping": { @@ -1045,6 +1043,7 @@ "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-2.0.0.tgz", "integrity": "sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==", "dev": true, + "peer": true, "engines": { "node": ">= 10" } @@ -1128,6 +1127,7 @@ "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-20.0.1.tgz", "integrity": "sha512-d0r18sZPmMQr1eG35u12FZfhIXNrnsPU/g5wvRKCUf/tOGilKKwYMYGqh33BNR6ba+2gkHw1EUiHoN3mn7E5IQ==", "dev": true, + "peer": true, "dependencies": { "@types/node": "*", "@types/tough-cookie": "*", @@ -1135,19 +1135,13 @@ } }, "node_modules/@types/node": { - "version": "20.4.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.2.tgz", - "integrity": "sha512-Dd0BYtWgnWJKwO1jkmTrzofjK2QXXcai0dmtzvIBhcA+RsG5h8R3xlyta0kGOZRNfL9GuRtb1knmPEhQrePCEw==", - "dev": true - }, - "node_modules/@types/node-fetch": { - "version": "2.6.11", - "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.11.tgz", - "integrity": "sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==", + "version": "20.17.19", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.19.tgz", + "integrity": "sha512-LEwC7o1ifqg/6r2gn9Dns0f1rhK+fPFDoMiceTJ6kWmVk6bgXBI/9IOWfVan4WiAavK9pIVWdX0/e3J+eEUh5A==", "dev": true, + "license": "MIT", "dependencies": { - "@types/node": "*", - "form-data": "^4.0.0" + "undici-types": "~6.19.2" } }, "node_modules/@types/stack-utils": { @@ -1160,7 +1154,8 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.3.tgz", "integrity": "sha512-THo502dA5PzG/sfQH+42Lw3fvmYkceefOspdCwpHRul8ik2Jv1K8I5OZz1AT3/rs46kwgMCe9bSBmDLYkkOMGg==", - "dev": true + "dev": true, + "peer": true }, "node_modules/@types/ws": { "version": "8.5.10", @@ -1190,13 +1185,15 @@ "version": "2.0.6", "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", - "dev": true + "dev": true, + "peer": true }, "node_modules/acorn": { "version": "8.10.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", "dev": true, + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -1209,6 +1206,7 @@ "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-7.0.1.tgz", "integrity": "sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==", "dev": true, + "peer": true, "dependencies": { "acorn": "^8.1.0", "acorn-walk": "^8.0.2" @@ -1219,6 +1217,7 @@ "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", "dev": true, + "peer": true, "engines": { "node": ">=0.4.0" } @@ -1228,6 +1227,7 @@ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", "dev": true, + "peer": true, "dependencies": { "debug": "4" }, @@ -1300,7 +1300,8 @@ "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true + "dev": true, + "peer": true }, "node_modules/babel-jest": { "version": "29.7.0", @@ -1633,6 +1634,7 @@ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "dev": true, + "peer": true, "dependencies": { "delayed-stream": "~1.0.0" }, @@ -1691,13 +1693,15 @@ "version": "0.5.0", "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz", "integrity": "sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==", - "dev": true + "dev": true, + "peer": true }, "node_modules/cssstyle": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", "dev": true, + "peer": true, "dependencies": { "cssom": "~0.3.6" }, @@ -1709,13 +1713,15 @@ "version": "0.3.8", "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", - "dev": true + "dev": true, + "peer": true }, "node_modules/data-urls": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-3.0.2.tgz", "integrity": "sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==", "dev": true, + "peer": true, "dependencies": { "abab": "^2.0.6", "whatwg-mimetype": "^3.0.0", @@ -1730,6 +1736,7 @@ "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", "dev": true, + "peer": true, "dependencies": { "punycode": "^2.1.1" }, @@ -1742,6 +1749,7 @@ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", "dev": true, + "peer": true, "engines": { "node": ">=12" } @@ -1751,6 +1759,7 @@ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", "dev": true, + "peer": true, "dependencies": { "tr46": "^3.0.0", "webidl-conversions": "^7.0.0" @@ -1780,7 +1789,8 @@ "version": "10.4.3", "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", - "dev": true + "dev": true, + "peer": true }, "node_modules/dedent": { "version": "1.5.1", @@ -1810,6 +1820,7 @@ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", "dev": true, + "peer": true, "engines": { "node": ">=0.4.0" } @@ -1837,6 +1848,7 @@ "resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz", "integrity": "sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==", "dev": true, + "peer": true, "dependencies": { "webidl-conversions": "^7.0.0" }, @@ -1849,6 +1861,7 @@ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", "dev": true, + "peer": true, "engines": { "node": ">=12" } @@ -1882,6 +1895,7 @@ "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", "dev": true, + "peer": true, "engines": { "node": ">=0.12" }, @@ -1921,6 +1935,7 @@ "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", "dev": true, + "peer": true, "dependencies": { "esprima": "^4.0.1", "estraverse": "^5.2.0", @@ -1955,6 +1970,7 @@ "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, + "peer": true, "engines": { "node": ">=4.0" } @@ -1964,6 +1980,7 @@ "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", "dev": true, + "peer": true, "engines": { "node": ">=0.10.0" } @@ -2070,6 +2087,7 @@ "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", "dev": true, + "peer": true, "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -2220,6 +2238,7 @@ "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz", "integrity": "sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==", "dev": true, + "peer": true, "dependencies": { "whatwg-encoding": "^2.0.0" }, @@ -2238,6 +2257,7 @@ "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-5.0.0.tgz", "integrity": "sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==", "dev": true, + "peer": true, "dependencies": { "@tootallnate/once": "2", "agent-base": "6", @@ -2252,6 +2272,7 @@ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", "dev": true, + "peer": true, "dependencies": { "agent-base": "6", "debug": "4" @@ -2274,6 +2295,7 @@ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", "dev": true, + "peer": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" }, @@ -2374,7 +2396,8 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", - "dev": true + "dev": true, + "peer": true }, "node_modules/is-stream": { "version": "2.0.1", @@ -2690,6 +2713,7 @@ "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-29.7.0.tgz", "integrity": "sha512-k9iQbsf9OyOfdzWH8HDmrRT0gSIcX+FLNW7IQq94tFX0gynPwqDTW0Ho6iMVNjGz/nb+l/vW3dWM2bbLLpkbXA==", "dev": true, + "peer": true, "dependencies": { "@jest/environment": "^29.7.0", "@jest/fake-timers": "^29.7.0", @@ -2729,6 +2753,19 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/jest-fixed-jsdom": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/jest-fixed-jsdom/-/jest-fixed-jsdom-0.0.9.tgz", + "integrity": "sha512-KPfqh2+sn5q2B+7LZktwDcwhCpOpUSue8a1I+BcixWLOQoEVyAjAGfH+IYZGoxZsziNojoHGRTC8xRbB1wDD4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.0.0" + }, + "peerDependencies": { + "jest-environment-jsdom": ">=28.0.0" + } + }, "node_modules/jest-get-type": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", @@ -3132,6 +3169,7 @@ "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-20.0.3.tgz", "integrity": "sha512-SYhBvTh89tTfCD/CRdSOm13mOBa42iTaTyfyEWBdKcGdPxPtLFBXuHR8XHb33YNYaP+lLbmSvBTsnoesCNJEsQ==", "dev": true, + "peer": true, "dependencies": { "abab": "^2.0.6", "acorn": "^8.8.1", @@ -3177,6 +3215,7 @@ "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", "dev": true, + "peer": true, "dependencies": { "punycode": "^2.1.1" }, @@ -3189,6 +3228,7 @@ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", "dev": true, + "peer": true, "engines": { "node": ">=12" } @@ -3198,6 +3238,7 @@ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", "dev": true, + "peer": true, "dependencies": { "tr46": "^3.0.0", "webidl-conversions": "^7.0.0" @@ -3373,6 +3414,7 @@ "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "dev": true, + "peer": true, "engines": { "node": ">= 0.6" } @@ -3382,6 +3424,7 @@ "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dev": true, + "peer": true, "dependencies": { "mime-db": "1.52.0" }, @@ -3448,25 +3491,6 @@ "node": ">=10.5.0" } }, - "node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -3504,7 +3528,8 @@ "version": "2.2.7", "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.7.tgz", "integrity": "sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==", - "dev": true + "dev": true, + "peer": true }, "node_modules/once": { "version": "1.4.0", @@ -3604,6 +3629,7 @@ "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", "dev": true, + "peer": true, "dependencies": { "entities": "^4.4.0" }, @@ -3726,13 +3752,15 @@ "version": "1.9.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", - "dev": true + "dev": true, + "peer": true }, "node_modules/punycode": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", "dev": true, + "peer": true, "engines": { "node": ">=6" } @@ -3757,7 +3785,8 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", - "dev": true + "dev": true, + "peer": true }, "node_modules/react-is": { "version": "18.2.0", @@ -3778,7 +3807,8 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", - "dev": true + "dev": true, + "peer": true }, "node_modules/resolve": { "version": "1.22.8", @@ -3831,13 +3861,15 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true + "dev": true, + "peer": true }, "node_modules/saxes": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", "dev": true, + "peer": true, "dependencies": { "xmlchars": "^2.2.0" }, @@ -4030,7 +4062,8 @@ "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", - "dev": true + "dev": true, + "peer": true }, "node_modules/test-exclude": { "version": "6.0.0", @@ -4046,12 +4079,6 @@ "node": ">=8" } }, - "node_modules/text-encoding-polyfill": { - "version": "0.6.7", - "resolved": "https://registry.npmjs.org/text-encoding-polyfill/-/text-encoding-polyfill-0.6.7.tgz", - "integrity": "sha512-/DZ1XJqhbqRkCop6s9ZFu8JrFRwmVuHg4quIRm+ziFkR3N3ec6ck6yBvJ1GYeEQZhLVwRW0rZE+C3SSJpy0RTg==", - "dev": true - }, "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -4084,6 +4111,7 @@ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", "dev": true, + "peer": true, "dependencies": { "psl": "^1.1.33", "punycode": "^2.1.1", @@ -4094,11 +4122,6 @@ "node": ">=6" } }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" - }, "node_modules/ts-jest": { "version": "29.1.2", "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.1.2.tgz", @@ -4218,23 +4241,40 @@ } }, "node_modules/typescript": { - "version": "4.7.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", - "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", - "dev": true, + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz", + "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", + "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { - "node": ">=4.2.0" + "node": ">=14.17" + } + }, + "node_modules/undici": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.2.0.tgz", + "integrity": "sha512-klt+0S55GBViA9nsq48/NSCo4YX5mjydjypxD7UmHh/brMu8h/Mhd/F7qAeoH2NOO8SDTk6kjnTFc4WpzmfYpQ==", + "license": "MIT", + "engines": { + "node": ">=20.18.1" } }, + "node_modules/undici-types": { + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "dev": true, + "license": "MIT" + }, "node_modules/universalify": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", "dev": true, + "peer": true, "engines": { "node": ">= 4.0.0" } @@ -4274,6 +4314,7 @@ "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", "dev": true, + "peer": true, "dependencies": { "querystringify": "^2.1.1", "requires-port": "^1.0.0" @@ -4298,6 +4339,7 @@ "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz", "integrity": "sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw==", "dev": true, + "peer": true, "dependencies": { "xml-name-validator": "^4.0.0" }, @@ -4322,16 +4364,12 @@ "node": ">= 14" } }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" - }, "node_modules/whatwg-encoding": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz", "integrity": "sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==", "dev": true, + "peer": true, "dependencies": { "iconv-lite": "0.6.3" }, @@ -4344,19 +4382,11 @@ "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", "dev": true, + "peer": true, "engines": { "node": ">=12" } }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -4413,6 +4443,7 @@ "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.1.tgz", "integrity": "sha512-4OOseMUq8AzRBI/7SLMUwO+FEDnguetSk7KMb1sHwvF2w2Wv5Hoj0nlifx8vtGsftE/jWHojPy8sMMzYLJ2G/A==", "dev": true, + "peer": true, "engines": { "node": ">=10.0.0" }, @@ -4434,6 +4465,7 @@ "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-4.0.0.tgz", "integrity": "sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==", "dev": true, + "peer": true, "engines": { "node": ">=12" } @@ -4442,7 +4474,8 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", - "dev": true + "dev": true, + "peer": true }, "node_modules/y18n": { "version": "5.0.8", diff --git a/ecosystem-tests/node-ts-cjs/package.json b/ecosystem-tests/node-ts-cjs/package.json index 039b37a3d..7946e8eae 100644 --- a/ecosystem-tests/node-ts-cjs/package.json +++ b/ecosystem-tests/node-ts-cjs/package.json @@ -4,26 +4,22 @@ "main": "index.js", "private": true, "scripts": { - "tsc": "tsc && tsc -p tsconfig.nodenext.json && tsc -p node_modules/openai/src/tsconfig.json", + "tsc": "tsc && tsc -p tsconfig.nodenext.json", "test": "jest" }, "dependencies": { "formdata-node": "^4.4.1", - "node-fetch": "^2.6.1", - "tsconfig-paths": "^4.0.0" + "tsconfig-paths": "^4.0.0", + "typescript": "^5.7.3", + "undici": "^7.2.0" }, "devDependencies": { - "@types/node": "20.4.2", - "@types/node-fetch": "^2.6.1", + "@types/node": "^20.14.8", "@types/ws": "^8.5.4", "fastest-levenshtein": "^1.0.16", "jest": "^29.5.0", - "jest-environment-jsdom": "^29.7.0", - "text-encoding-polyfill": "^0.6.7", - "ts-jest": "^29.1.0", - "typescript": "4.7.4" + "jest-fixed-jsdom": "^0.0.9", + "ts-jest": "^29.1.0" }, - "overrides": { - "@types/node": "20.4.2" - } + "type": "commonjs" } diff --git a/ecosystem-tests/node-ts-cjs/tests/late-shim-errors.ts b/ecosystem-tests/node-ts-cjs/tests/late-shim-errors.ts deleted file mode 100644 index 6b9c4d95c..000000000 --- a/ecosystem-tests/node-ts-cjs/tests/late-shim-errors.ts +++ /dev/null @@ -1,8 +0,0 @@ -export {}; - -test('throws if shims are imported after openai', async () => { - await import('openai'); - await expect(() => import('openai/shims/web')).rejects.toThrow( - `you must \`import 'openai/shims/web'\` before importing anything else from openai`, - ); -}); diff --git a/ecosystem-tests/node-ts-cjs/tests/multiple-shim-errors.ts b/ecosystem-tests/node-ts-cjs/tests/multiple-shim-errors.ts deleted file mode 100644 index 92261fd58..000000000 --- a/ecosystem-tests/node-ts-cjs/tests/multiple-shim-errors.ts +++ /dev/null @@ -1,8 +0,0 @@ -export {}; - -test('throws if multiple shims are imported', async () => { - await import('openai/shims/node'); - await expect(() => import('openai/shims/web')).rejects.toThrow( - `can't \`import 'openai/shims/web'\` after \`import 'openai/shims/node'\``, - ); -}); diff --git a/ecosystem-tests/node-ts-cjs/tests/shims.ts b/ecosystem-tests/node-ts-cjs/tests/shims.ts deleted file mode 100644 index d0b04bac5..000000000 --- a/ecosystem-tests/node-ts-cjs/tests/shims.ts +++ /dev/null @@ -1,12 +0,0 @@ -import 'openai/shims/node'; -import * as shims from 'openai/_shims/index'; -import * as fd from 'formdata-node'; - -function typeTests(x: shims.Request) { - const url: string = x.url; -} - -test('openai/shims/node', () => { - expect(shims.kind).toEqual('node'); - expect(shims.File).toBe(fd.File); -}); diff --git a/ecosystem-tests/node-ts-cjs/tests/test-jsdom-compat-error.ts b/ecosystem-tests/node-ts-cjs/tests/test-jsdom-compat-error.ts deleted file mode 100644 index 066fc3dc2..000000000 --- a/ecosystem-tests/node-ts-cjs/tests/test-jsdom-compat-error.ts +++ /dev/null @@ -1,11 +0,0 @@ -/** - * @jest-environment jsdom - */ - -export {}; - -it(`throws when fetch API types are missing`, async () => { - await expect(() => import('openai')).rejects.toThrow( - 'this environment is missing the following Web Fetch API type', - ); -}); diff --git a/ecosystem-tests/node-ts-cjs/tests/test-jsdom.ts b/ecosystem-tests/node-ts-cjs/tests/test-jsdom.ts index 15b9df7c9..7910f62bd 100644 --- a/ecosystem-tests/node-ts-cjs/tests/test-jsdom.ts +++ b/ecosystem-tests/node-ts-cjs/tests/test-jsdom.ts @@ -1,12 +1,8 @@ /** - * @jest-environment jsdom + * @jest-environment jest-fixed-jsdom */ -import 'openai/shims/node'; import OpenAI, { toFile } from 'openai'; -import fetch from 'node-fetch'; import { distance } from 'fastest-levenshtein'; -// @ts-ignore -import { TextEncoder } from 'text-encoding-polyfill'; const url = 'https://audio-samples.github.io/samples/mp3/blizzard_biased/sample-1.mp3'; const filename = 'sample-1.mp3'; @@ -15,7 +11,10 @@ const correctAnswer = 'It was anxious to find him no one that expectation of a man who were giving his father enjoyment. But he was avoided in sight in the minister to which indeed,'; const model = 'whisper-1'; -const client = new OpenAI({ apiKey: process.env['OPENAI_API_KEY'], dangerouslyAllowBrowser: true }); +const client = new OpenAI({ + apiKey: process.env['OPENAI_API_KEY'], + dangerouslyAllowBrowser: true, +}); async function typeTests() { // @ts-expect-error this should error if the `Uploadable` type was resolved correctly @@ -81,8 +80,7 @@ it(`streaming works`, async function () { it.skip('handles builtinFile', async function () { const file = await fetch(url) - .then((x) => x.arrayBuffer()) - // @ts-ignore avoid DOM lib for testing purposes + .then((x) => x.blob()) .then((x) => new File([x], filename)); const result = await client.audio.transcriptions.create({ file, model }); @@ -101,55 +99,30 @@ const fineTune = `{"prompt": "", "completion": " { it('handles builtin Blob', async function () { const result = await client.files.create({ - file: await toFile( - // @ts-ignore avoid DOM lib for testing purposes - new Blob([new TextEncoder().encode(fineTune)]), - 'finetune.jsonl', - ), + file: await toFile(new Blob([new TextEncoder().encode(fineTune)]), 'finetune.jsonl'), purpose: 'fine-tune', }); expect(result.filename).toEqual('finetune.jsonl'); }); it('handles Uint8Array', async function () { const result = await client.files.create({ - file: await toFile( - // @ts-ignore avoid DOM lib for testing purposes - new TextEncoder().encode(fineTune), - 'finetune.jsonl', - ), + file: await toFile(new TextEncoder().encode(fineTune), 'finetune.jsonl'), purpose: 'fine-tune', }); expect(result.filename).toEqual('finetune.jsonl'); }); it('handles ArrayBuffer', async function () { const result = await client.files.create({ - file: await toFile( - // @ts-ignore avoid DOM lib for testing purposes - new TextEncoder().encode(fineTune).buffer, - 'finetune.jsonl', - ), + file: await toFile(new TextEncoder().encode(fineTune).buffer, 'finetune.jsonl'), purpose: 'fine-tune', }); expect(result.filename).toEqual('finetune.jsonl'); }); it('handles DataView', async function () { const result = await client.files.create({ - file: await toFile( - // @ts-ignore avoid DOM lib for testing purposes - new DataView(new TextEncoder().encode(fineTune).buffer), - 'finetune.jsonl', - ), + file: await toFile(new DataView(new TextEncoder().encode(fineTune).buffer), 'finetune.jsonl'), purpose: 'fine-tune', }); expect(result.filename).toEqual('finetune.jsonl'); }); }); - -test('query strings', () => { - expect( - decodeURIComponent((client as any).stringifyQuery({ foo: { nested: { a: true, b: 'foo' } } })), - ).toEqual('foo[nested][a]=true&foo[nested][b]=foo'); - expect( - decodeURIComponent((client as any).stringifyQuery({ foo: { nested: { a: ['hello', 'world'] } } })), - ).toEqual('foo[nested][a][]=hello&foo[nested][a][]=world'); -}); diff --git a/ecosystem-tests/node-ts-cjs/tests/test-node.ts b/ecosystem-tests/node-ts-cjs/tests/test-node.ts index 3f6e5d572..ebdc4e091 100644 --- a/ecosystem-tests/node-ts-cjs/tests/test-node.ts +++ b/ecosystem-tests/node-ts-cjs/tests/test-node.ts @@ -1,11 +1,11 @@ -import 'openai/shims/node'; import OpenAI, { toFile } from 'openai'; import { TranscriptionCreateParams } from 'openai/resources/audio/transcriptions'; -import fetch from 'node-fetch'; +import * as undici from 'undici'; import { File as FormDataFile, Blob as FormDataBlob } from 'formdata-node'; import * as fs from 'fs'; import { distance } from 'fastest-levenshtein'; import { ChatCompletion } from 'openai/resources/chat/completions'; +import { File } from 'node:buffer'; const url = 'https://audio-samples.github.io/samples/mp3/blizzard_biased/sample-1.mp3'; const filename = 'sample-1.mp3'; @@ -65,13 +65,12 @@ it(`raw response`, async function () { }) .asResponse(); - // test that we can use node-fetch Response API + const decoder = new TextDecoder(); const chunks: string[] = []; - response.body.on('data', (chunk) => chunks.push(chunk)); - await new Promise((resolve, reject) => { - response.body.once('end', resolve); - response.body.once('error', reject); - }); + for await (const chunk of response.body!) { + chunks.push(decoder.decode(chunk)); + } + const json: ChatCompletion = JSON.parse(chunks.join('')); expect(json.choices[0]?.message.content || '').toBeSimilarTo('This is a test', 10); }); @@ -89,30 +88,38 @@ it(`streaming works`, async function () { expect(chunks.map((c) => c.choices[0]?.delta.content || '').join('')).toBeSimilarTo('This is a test', 10); }); -it('handles formdata-node File', async function () { +test(`proxied request`, async function () { + const dispatcher = new undici.ProxyAgent(process.env['ECOSYSTEM_TESTS_PROXY']!); + const client = new OpenAI({ + fetchOptions: { + dispatcher, + }, + }); + const completion = await client.chat.completions.create({ + model: 'gpt-4', + messages: [{ role: 'user', content: 'Say this is a test' }], + }); + expect(completion.choices[0]?.message?.content).toBeSimilarTo('This is a test', 10); +}); + +it('handles builtinFile', async function () { const file = await fetch(url) .then((x) => x.arrayBuffer()) - .then((x) => new FormDataFile([x], filename)); - - const params: TranscriptionCreateParams = { file, model }; + .then( + (x) => + new File( + [ + // @ts-ignore array buffer can't be passed to File at the type-level + x, + ], + filename, + ), + ); - const result = await client.audio.transcriptions.create(params); + const result = await client.audio.transcriptions.create({ file, model }); expect(result.text).toBeSimilarTo(correctAnswer, 12); }); -// @ts-ignore avoid DOM lib for testing purposes -if (typeof File !== 'undefined') { - it('handles builtinFile', async function () { - const file = await fetch(url) - .then((x) => x.arrayBuffer()) - // @ts-ignore avoid DOM lib for testing purposes - .then((x) => new File([x], filename)); - - const result = await client.audio.transcriptions.create({ file, model }); - expect(result.text).toBeSimilarTo(correctAnswer, 12); - }); -} - it('handles Response', async function () { const file = await fetch(url); @@ -133,26 +140,15 @@ const fineTune = `{"prompt": "", "completion": " { it('handles form-data Blob', async function () { const result = await client.files.create({ - file: await toFile( - new FormDataBlob([ - // @ts-ignore avoid DOM lib for testing purposes - new TextEncoder().encode(fineTune), - ]), - 'finetune.jsonl', - ), + file: await toFile(new FormDataBlob([new TextEncoder().encode(fineTune)]), 'finetune.jsonl'), purpose: 'fine-tune', }); expect(result.filename).toEqual('finetune.jsonl'); }); - // @ts-ignore avoid DOM lib for testing purposes if (typeof Blob !== 'undefined') { it('handles builtin Blob', async function () { const result = await client.files.create({ - file: await toFile( - // @ts-ignore avoid DOM lib for testing purposes - new Blob([new TextEncoder().encode(fineTune)]), - 'finetune.jsonl', - ), + file: await toFile(new Blob([new TextEncoder().encode(fineTune)]), 'finetune.jsonl'), purpose: 'fine-tune', }); expect(result.filename).toEqual('finetune.jsonl'); @@ -160,44 +156,36 @@ describe('toFile', () => { } it('handles Uint8Array', async function () { const result = await client.files.create({ - file: await toFile( - // @ts-ignore avoid DOM lib for testing purposes - new TextEncoder().encode(fineTune), - 'finetune.jsonl', - ), + file: await toFile(new TextEncoder().encode(fineTune), 'finetune.jsonl'), purpose: 'fine-tune', }); expect(result.filename).toEqual('finetune.jsonl'); }); it('handles ArrayBuffer', async function () { const result = await client.files.create({ - file: await toFile( - // @ts-ignore avoid DOM lib for testing purposes - new TextEncoder().encode(fineTune).buffer, - 'finetune.jsonl', - ), + file: await toFile(new TextEncoder().encode(fineTune).buffer, 'finetune.jsonl'), purpose: 'fine-tune', }); expect(result.filename).toEqual('finetune.jsonl'); }); it('handles DataView', async function () { const result = await client.files.create({ - file: await toFile( - // @ts-ignore avoid DOM lib for testing purposes - new DataView(new TextEncoder().encode(fineTune).buffer), - 'finetune.jsonl', - ), + file: await toFile(new DataView(new TextEncoder().encode(fineTune).buffer), 'finetune.jsonl'), purpose: 'fine-tune', }); expect(result.filename).toEqual('finetune.jsonl'); }); -}); -test('query strings', () => { - expect( - decodeURIComponent((client as any).stringifyQuery({ foo: { nested: { a: true, b: 'foo' } } })), - ).toEqual('foo[nested][a]=true&foo[nested][b]=foo'); - expect( - decodeURIComponent((client as any).stringifyQuery({ foo: { nested: { a: ['hello', 'world'] } } })), - ).toEqual('foo[nested][a][]=hello&foo[nested][a][]=world'); + it('handles formdata-node File', async function () { + const file = await fetch(url) + .then((x) => x.arrayBuffer()) + .then((x) => toFile(new FormDataFile([x], filename))); + + expect(file.name).toEqual(filename); + + const params: TranscriptionCreateParams = { file, model }; + + const result = await client.audio.transcriptions.create(params); + expect(result.text).toBeSimilarTo(correctAnswer, 12); + }); }); diff --git a/ecosystem-tests/node-ts-cjs/tsconfig.json b/ecosystem-tests/node-ts-cjs/tsconfig.json index d1ad90efd..a7b5e119f 100644 --- a/ecosystem-tests/node-ts-cjs/tsconfig.json +++ b/ecosystem-tests/node-ts-cjs/tsconfig.json @@ -11,6 +11,7 @@ "target": "ES2015", "lib": ["ES2015"], "jsx": "react", + "types": ["node", "jest"], /* Modules */ "module": "commonjs", diff --git a/ecosystem-tests/node-ts-cjs/tsconfig.nodenext.json b/ecosystem-tests/node-ts-cjs/tsconfig.nodenext.json index 0efe77b4e..eb9e3ec20 100644 --- a/ecosystem-tests/node-ts-cjs/tsconfig.nodenext.json +++ b/ecosystem-tests/node-ts-cjs/tsconfig.nodenext.json @@ -11,9 +11,10 @@ "target": "ES2015", "lib": ["ES2015"], "jsx": "react", + "types": ["node", "jest"], /* Modules */ - "module": "commonjs", + "module": "NodeNext", "rootDir": "./", "moduleResolution": "NodeNext", "baseUrl": "./", diff --git a/ecosystem-tests/node-ts-es2020/index.ts b/ecosystem-tests/node-ts-es2020/index.ts deleted file mode 100644 index d92cc2720..000000000 --- a/ecosystem-tests/node-ts-es2020/index.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { zodResponseFormat } from 'openai/helpers/zod'; -import OpenAI from 'openai/index'; -import { z } from 'zod'; - -const Step = z.object({ - explanation: z.string(), - output: z.string(), -}); - -const MathResponse = z.object({ - steps: z.array(Step), - final_answer: z.string(), -}); - -async function main() { - const client = new OpenAI(); - - const completion = await client.beta.chat.completions.parse({ - model: 'gpt-4o-2024-08-06', - messages: [ - { role: 'system', content: 'You are a helpful math tutor.' }, - { role: 'user', content: 'solve 8x + 31 = 2' }, - ], - response_format: zodResponseFormat(MathResponse, 'math_response'), - }); - - console.dir(completion, { depth: 5 }); - - const message = completion.choices[0]?.message; - if (message?.parsed) { - console.log(message.parsed.steps); - console.log(`answer: ${message.parsed.final_answer}`); - } -} - -main(); diff --git a/ecosystem-tests/node-ts-es2020/package-lock.json b/ecosystem-tests/node-ts-es2020/package-lock.json deleted file mode 100644 index 5ae1d5aa0..000000000 --- a/ecosystem-tests/node-ts-es2020/package-lock.json +++ /dev/null @@ -1,193 +0,0 @@ -{ - "name": "node-ts-es2020", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "node-ts-es2020", - "version": "1.0.0", - "dependencies": { - "ts-node": "^10.9.2", - "zod": "^3.23.8" - } - }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", - "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" - }, - "node_modules/@tsconfig/node10": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", - "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==" - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==" - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==" - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", - "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==" - }, - "node_modules/@types/node": { - "version": "20.4.2", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.2.tgz", - "integrity": "sha512-Dd0BYtWgnWJKwO1jkmTrzofjK2QXXcai0dmtzvIBhcA+RsG5h8R3xlyta0kGOZRNfL9GuRtb1knmPEhQrePCEw==", - "peer": true - }, - "node_modules/acorn": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", - "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-walk": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", - "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==" - }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==" - }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==" - }, - "node_modules/ts-node": { - "version": "10.9.2", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", - "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", - "dependencies": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-esm": "dist/bin-esm.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } - } - }, - "node_modules/typescript": { - "version": "4.7.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.7.4.tgz", - "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==", - "peer": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==" - }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "engines": { - "node": ">=6" - } - }, - "node_modules/zod": { - "version": "3.23.8", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz", - "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - } - } -} diff --git a/ecosystem-tests/node-ts-es2020/package.json b/ecosystem-tests/node-ts-es2020/package.json deleted file mode 100644 index ea7e488f5..000000000 --- a/ecosystem-tests/node-ts-es2020/package.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "name": "node-ts-es2020", - "version": "1.0.0", - "main": "index.js", - "scripts": { - "tsc": "tsc && tsc -p tsconfig.nodenext.json && tsc -p node_modules/openai/src/tsconfig.json", - "main": "ts-node index.ts" - }, - "dependencies": { - "ts-node": "^10.9.2", - "zod": "^3.23.8" - }, - "overrides": { - "@types/node": "20.4.2" - } -} diff --git a/ecosystem-tests/node-ts-es2020/tsconfig.base.json b/ecosystem-tests/node-ts-es2020/tsconfig.base.json deleted file mode 100644 index 8edad9422..000000000 --- a/ecosystem-tests/node-ts-es2020/tsconfig.base.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "compilerOptions": { - "target": "es2020", - "module": "commonjs", - "lib": ["es2020", "dom"], - "allowJs": false, - "declaration": true, - "declarationMap": true, - "sourceMap": true, - "removeComments": true, - "forceConsistentCasingInFileNames": true, - "downlevelIteration": true, - "strict": true, - "moduleResolution": "node", - "paths": {}, - "typeRoots": ["node_modules/@types"], - "types": ["node"], - "allowSyntheticDefaultImports": false, - "experimentalDecorators": true, - "emitDecoratorMetadata": true, - "resolveJsonModule": true, - "incremental": true, - "strictBindCallApply": true, - "strictFunctionTypes": true, - "strictNullChecks": true, - "strictPropertyInitialization": true, - "noImplicitAny": true, - "noImplicitThis": true, - "noImplicitReturns": true, - "noUnusedParameters": true, - "noUnusedLocals": true, - "noFallthroughCasesInSwitch": true, - "preserveSymlinks": true, - "suppressImplicitAnyIndexErrors": true - }, - "exclude": ["node_modules"] -} diff --git a/ecosystem-tests/node-ts-es2020/tsconfig.json b/ecosystem-tests/node-ts-es2020/tsconfig.json deleted file mode 100644 index aa3b68f53..000000000 --- a/ecosystem-tests/node-ts-es2020/tsconfig.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "extends": "./tsconfig.base.json", - "ts-node": { - "swc": true, - "transpileOnly": true - }, - "compilerOptions": { - "declaration": false, - "declarationMap": false, - "allowJs": true, - "checkJs": false, - "outDir": "./dist", - "baseUrl": "./", - "types": ["node", "jest"], - "paths": {} - }, - "include": ["index.ts", "tsconfig.json", "jest.config.ts", ".eslintrc.js"] -} diff --git a/ecosystem-tests/node-ts-es2020/tsconfig.nodenext.json b/ecosystem-tests/node-ts-es2020/tsconfig.nodenext.json deleted file mode 100644 index 97df071fb..000000000 --- a/ecosystem-tests/node-ts-es2020/tsconfig.nodenext.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "include": ["tests/*.ts", "index.ts"], - "exclude": ["tests/*-shim-errors.ts"], - - "compilerOptions": { - /* Visit https://aka.ms/tsconfig.json to read more about this file */ - /* Projects */ - "incremental": true, - - /* Language and Environment */ - "target": "ES2015", - "lib": ["ES2015"], - "jsx": "react", - - /* Modules */ - "module": "commonjs", - "rootDir": "./", - "moduleResolution": "NodeNext", - "baseUrl": "./", - "paths": { - "~/*": ["*"] - }, - "resolveJsonModule": true, - "composite": true, - - /* Emit */ - "outDir": "node_modules", - "noEmit": true, - - /* Interop Constraints */ - "isolatedModules": true, - "allowSyntheticDefaultImports": true, - /* "esModuleInterop": true, */ - "forceConsistentCasingInFileNames": true, - "allowJs": true, - "checkJs": true, - - /* Experimental Features */ - "experimentalDecorators": true, - - /* Type Checking */ - "strict": true, - "noImplicitAny": true, - "strictNullChecks": true, - "strictFunctionTypes": true, - "strictBindCallApply": true, - "strictPropertyInitialization": true, - "noImplicitThis": true, - "alwaysStrict": true, - "noUncheckedIndexedAccess": true, - "noImplicitOverride": true, - "noPropertyAccessFromIndexSignature": true, - "skipLibCheck": false - } -} diff --git a/ecosystem-tests/node-ts-esm-auto/esnext-type-tests.ts b/ecosystem-tests/node-ts-esm-auto/esnext-type-tests.ts index c47ddc2a5..e70cad642 100644 --- a/ecosystem-tests/node-ts-esm-auto/esnext-type-tests.ts +++ b/ecosystem-tests/node-ts-esm-auto/esnext-type-tests.ts @@ -1,5 +1,6 @@ -import * as shims from 'openai/_shims/index'; +import OpenAI from 'openai'; -function typeTests(x: shims.Request) { - const url: string = x.url; +async function typeTests(client: OpenAI) { + const response = await client.chat.completions.create({ model: 'gpt-4o', messages: [] }).asResponse(); + const url: string = response.url; } diff --git a/ecosystem-tests/node-ts-esm-auto/package-lock.json b/ecosystem-tests/node-ts-esm-auto/package-lock.json index 3e4438d05..729b0f2e9 100644 --- a/ecosystem-tests/node-ts-esm-auto/package-lock.json +++ b/ecosystem-tests/node-ts-esm-auto/package-lock.json @@ -8,8 +8,7 @@ "name": "node-ts-esm-auto", "version": "0.0.1", "dependencies": { - "formdata-node": "^5.0.1", - "node-fetch": "^3.0.0" + "formdata-node": "^5.0.1" }, "devDependencies": { "@types/node": "^20.3.1", @@ -1653,14 +1652,6 @@ "node": ">= 8" } }, - "node_modules/data-uri-to-buffer": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", - "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", - "engines": { - "node": ">= 12" - } - }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -1864,36 +1855,6 @@ "bser": "2.1.1" } }, - "node_modules/fetch-blob": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", - "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "paypal", - "url": "https://paypal.me/jimmywarting" - } - ], - "dependencies": { - "node-domexception": "^1.0.0", - "web-streams-polyfill": "^3.0.3" - }, - "engines": { - "node": "^12.20 || >= 14.13" - } - }, - "node_modules/fetch-blob/node_modules/web-streams-polyfill": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", - "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", - "engines": { - "node": ">= 8" - } - }, "node_modules/fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -1931,17 +1892,6 @@ "node": ">= 14.17" } }, - "node_modules/formdata-polyfill": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", - "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", - "dependencies": { - "fetch-blob": "^3.1.2" - }, - "engines": { - "node": ">=12.20.0" - } - }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -3108,23 +3058,6 @@ "node": ">=10.5.0" } }, - "node_modules/node-fetch": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", - "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", - "dependencies": { - "data-uri-to-buffer": "^4.0.0", - "fetch-blob": "^3.1.4", - "formdata-polyfill": "^4.0.10" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/node-fetch" - } - }, "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", diff --git a/ecosystem-tests/node-ts-esm-auto/package.json b/ecosystem-tests/node-ts-esm-auto/package.json index 7c227166c..28cf518c7 100644 --- a/ecosystem-tests/node-ts-esm-auto/package.json +++ b/ecosystem-tests/node-ts-esm-auto/package.json @@ -9,8 +9,7 @@ "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js" }, "dependencies": { - "formdata-node": "^5.0.1", - "node-fetch": "^3.0.0" + "formdata-node": "^5.0.1" }, "devDependencies": { "@types/node": "^20.3.1", diff --git a/ecosystem-tests/node-ts-esm-auto/tests/shims.ts b/ecosystem-tests/node-ts-esm-auto/tests/shims.ts deleted file mode 100644 index aed8e6497..000000000 --- a/ecosystem-tests/node-ts-esm-auto/tests/shims.ts +++ /dev/null @@ -1,5 +0,0 @@ -import * as shims from 'openai/_shims/index'; - -test('openai/shims/node', () => { - expect(shims.kind).toEqual('node'); -}); diff --git a/ecosystem-tests/node-ts-esm-auto/tests/test.ts b/ecosystem-tests/node-ts-esm-auto/tests/test.ts index 88beb2f54..855a925c5 100644 --- a/ecosystem-tests/node-ts-esm-auto/tests/test.ts +++ b/ecosystem-tests/node-ts-esm-auto/tests/test.ts @@ -1,11 +1,10 @@ -import 'openai/shims/node'; import OpenAI, { toFile } from 'openai'; import { TranscriptionCreateParams } from 'openai/resources/audio/transcriptions'; -import fetch from 'node-fetch'; import { File as FormDataFile, Blob as FormDataBlob } from 'formdata-node'; import * as fs from 'fs'; import { distance } from 'fastest-levenshtein'; import { ChatCompletion } from 'openai/resources/chat/completions'; +import { File } from 'node:buffer'; const url = 'https://audio-samples.github.io/samples/mp3/blizzard_biased/sample-1.mp3'; const filename = 'sample-1.mp3'; @@ -65,15 +64,12 @@ it(`raw response`, async function () { }) .asResponse(); - // test that we can use node-fetch Response API + const decoder = new TextDecoder(); const chunks: string[] = []; - const { body } = response; - if (!body) throw new Error(`expected response.body to be defined`); - body.on('data', (chunk) => chunks.push(chunk)); - await new Promise((resolve, reject) => { - body.once('end', resolve); - body.once('error', reject); - }); + for await (const chunk of response.body!) { + chunks.push(decoder.decode(chunk)); + } + const json: ChatCompletion = JSON.parse(chunks.join('')); expect(json.choices[0]?.message.content || '').toBeSimilarTo('This is a test', 10); }); @@ -91,30 +87,24 @@ it(`streaming works`, async function () { expect(chunks.map((c) => c.choices[0]?.delta.content || '').join('')).toBeSimilarTo('This is a test', 10); }); -it('handles formdata-node File', async function () { +it('handles builtinFile', async function () { const file = await fetch(url) .then((x) => x.arrayBuffer()) - .then((x) => new FormDataFile([x], filename)); - - const params: TranscriptionCreateParams = { file, model }; + .then( + (x) => + new File( + [ + // @ts-ignore array buffer can't be passed to File at the type-level + x, + ], + filename, + ), + ); - const result = await client.audio.transcriptions.create(params); + const result = await client.audio.transcriptions.create({ file, model }); expect(result.text).toBeSimilarTo(correctAnswer, 12); }); -// @ts-ignore avoid DOM lib for testing purposes -if (typeof File !== 'undefined') { - it('handles builtinFile', async function () { - const file = await fetch(url) - .then((x) => x.arrayBuffer()) - // @ts-ignore avoid DOM lib for testing purposes - .then((x) => new File([x], filename)); - - const result = await client.audio.transcriptions.create({ file, model }); - expect(result.text).toBeSimilarTo(correctAnswer, 12); - }); -} - it('handles Response', async function () { const file = await fetch(url); @@ -135,26 +125,15 @@ const fineTune = `{"prompt": "", "completion": " { it('handles form-data Blob', async function () { const result = await client.files.create({ - file: await toFile( - new FormDataBlob([ - // @ts-ignore avoid DOM lib for testing purposes - new TextEncoder().encode(fineTune), - ]), - 'finetune.jsonl', - ), + file: await toFile(new FormDataBlob([new TextEncoder().encode(fineTune)]), 'finetune.jsonl'), purpose: 'fine-tune', }); expect(result.filename).toEqual('finetune.jsonl'); }); - // @ts-ignore avoid DOM lib for testing purposes if (typeof Blob !== 'undefined') { it('handles builtin Blob', async function () { const result = await client.files.create({ - file: await toFile( - // @ts-ignore avoid DOM lib for testing purposes - new Blob([new TextEncoder().encode(fineTune)]), - 'finetune.jsonl', - ), + file: await toFile(new Blob([new TextEncoder().encode(fineTune)]), 'finetune.jsonl'), purpose: 'fine-tune', }); expect(result.filename).toEqual('finetune.jsonl'); @@ -162,44 +141,36 @@ describe('toFile', () => { } it('handles Uint8Array', async function () { const result = await client.files.create({ - file: await toFile( - // @ts-ignore avoid DOM lib for testing purposes - new TextEncoder().encode(fineTune), - 'finetune.jsonl', - ), + file: await toFile(new TextEncoder().encode(fineTune), 'finetune.jsonl'), purpose: 'fine-tune', }); expect(result.filename).toEqual('finetune.jsonl'); }); it('handles ArrayBuffer', async function () { const result = await client.files.create({ - file: await toFile( - // @ts-ignore avoid DOM lib for testing purposes - new TextEncoder().encode(fineTune).buffer, - 'finetune.jsonl', - ), + file: await toFile(new TextEncoder().encode(fineTune).buffer, 'finetune.jsonl'), purpose: 'fine-tune', }); expect(result.filename).toEqual('finetune.jsonl'); }); it('handles DataView', async function () { const result = await client.files.create({ - file: await toFile( - // @ts-ignore avoid DOM lib for testing purposes - new DataView(new TextEncoder().encode(fineTune).buffer), - 'finetune.jsonl', - ), + file: await toFile(new DataView(new TextEncoder().encode(fineTune).buffer), 'finetune.jsonl'), purpose: 'fine-tune', }); expect(result.filename).toEqual('finetune.jsonl'); }); -}); -test('query strings', () => { - expect( - decodeURIComponent((client as any).stringifyQuery({ foo: { nested: { a: true, b: 'foo' } } })), - ).toEqual('foo[nested][a]=true&foo[nested][b]=foo'); - expect( - decodeURIComponent((client as any).stringifyQuery({ foo: { nested: { a: ['hello', 'world'] } } })), - ).toEqual('foo[nested][a][]=hello&foo[nested][a][]=world'); + it('handles formdata-node File', async function () { + const file = await fetch(url) + .then((x) => x.arrayBuffer()) + .then((x) => toFile(new FormDataFile([x], filename))); + + expect(file.name).toEqual(filename); + + const params: TranscriptionCreateParams = { file, model }; + + const result = await client.audio.transcriptions.create(params); + expect(result.text).toBeSimilarTo(correctAnswer, 12); + }); }); diff --git a/ecosystem-tests/node-ts-esm-web/package-lock.json b/ecosystem-tests/node-ts-esm-web/package-lock.json index 118bf0909..695441ae3 100644 --- a/ecosystem-tests/node-ts-esm-web/package-lock.json +++ b/ecosystem-tests/node-ts-esm-web/package-lock.json @@ -8,8 +8,7 @@ "name": "node-ts-esm-web", "version": "0.0.1", "dependencies": { - "formdata-node": "^5.0.1", - "node-fetch": "^3.0.0" + "formdata-node": "^5.0.1" }, "devDependencies": { "@types/node": "^20.3.1", @@ -1653,14 +1652,6 @@ "node": ">= 8" } }, - "node_modules/data-uri-to-buffer": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", - "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", - "engines": { - "node": ">= 12" - } - }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -1864,36 +1855,6 @@ "bser": "2.1.1" } }, - "node_modules/fetch-blob": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", - "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "paypal", - "url": "https://paypal.me/jimmywarting" - } - ], - "dependencies": { - "node-domexception": "^1.0.0", - "web-streams-polyfill": "^3.0.3" - }, - "engines": { - "node": "^12.20 || >= 14.13" - } - }, - "node_modules/fetch-blob/node_modules/web-streams-polyfill": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", - "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", - "engines": { - "node": ">= 8" - } - }, "node_modules/fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -1931,17 +1892,6 @@ "node": ">= 14.17" } }, - "node_modules/formdata-polyfill": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", - "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", - "dependencies": { - "fetch-blob": "^3.1.2" - }, - "engines": { - "node": ">=12.20.0" - } - }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -3108,23 +3058,6 @@ "node": ">=10.5.0" } }, - "node_modules/node-fetch": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", - "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", - "dependencies": { - "data-uri-to-buffer": "^4.0.0", - "fetch-blob": "^3.1.4", - "formdata-polyfill": "^4.0.10" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/node-fetch" - } - }, "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", diff --git a/ecosystem-tests/node-ts-esm-web/package.json b/ecosystem-tests/node-ts-esm-web/package.json index 97a2309f8..f458a97a0 100644 --- a/ecosystem-tests/node-ts-esm-web/package.json +++ b/ecosystem-tests/node-ts-esm-web/package.json @@ -9,8 +9,7 @@ "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js" }, "dependencies": { - "formdata-node": "^5.0.1", - "node-fetch": "^3.0.0" + "formdata-node": "^5.0.1" }, "devDependencies": { "@types/node": "^20.3.1", diff --git a/ecosystem-tests/node-ts-esm-web/tests/shims.ts b/ecosystem-tests/node-ts-esm-web/tests/shims.ts deleted file mode 100644 index ea219ffb4..000000000 --- a/ecosystem-tests/node-ts-esm-web/tests/shims.ts +++ /dev/null @@ -1,12 +0,0 @@ -// shouldn't need extension, but Jest's ESM module resolution is broken -import 'openai/shims/web.mjs'; -import * as shims from 'openai/_shims/index'; - -function typeTests(x: shims.Request) { - const url: string = x.url; -} - -test('openai/shims/node', () => { - expect(shims.kind).toEqual('web'); - expect(shims.File).toEqual(File); -}); diff --git a/ecosystem-tests/node-ts-esm-web/tests/test.ts b/ecosystem-tests/node-ts-esm-web/tests/test.ts index 675fb9a73..520fe64b3 100644 --- a/ecosystem-tests/node-ts-esm-web/tests/test.ts +++ b/ecosystem-tests/node-ts-esm-web/tests/test.ts @@ -1,5 +1,3 @@ -// shouldn't need extension, but Jest's ESM module resolution is broken -import 'openai/shims/web.mjs'; import OpenAI, { toFile } from 'openai'; import { distance } from 'fastest-levenshtein'; import { ChatCompletion } from 'openai/resources/chat/completions'; @@ -104,7 +102,16 @@ if (typeof File !== 'undefined') { it('handles builtinFile', async function () { const file = await fetch(url) .then((x) => x.arrayBuffer()) - .then((x) => new File([x], filename)); + .then( + (x) => + new File( + [ + // @ts-ignore array buffer can't be passed to File at the type-level + x, + ], + filename, + ), + ); const result = await client.audio.transcriptions.create({ file, model }); expect(result.text).toBeSimilarTo(correctAnswer, 12); @@ -152,12 +159,3 @@ describe('toFile', () => { expect(result.filename).toEqual('finetune.jsonl'); }); }); - -test('query strings', () => { - expect( - decodeURIComponent((client as any).stringifyQuery({ foo: { nested: { a: true, b: 'foo' } } })), - ).toEqual('foo[nested][a]=true&foo[nested][b]=foo'); - expect( - decodeURIComponent((client as any).stringifyQuery({ foo: { nested: { a: ['hello', 'world'] } } })), - ).toEqual('foo[nested][a][]=hello&foo[nested][a][]=world'); -}); diff --git a/ecosystem-tests/node-ts-esm-web/types-test.ts b/ecosystem-tests/node-ts-esm-web/types-test.ts new file mode 100644 index 000000000..bff3349c5 --- /dev/null +++ b/ecosystem-tests/node-ts-esm-web/types-test.ts @@ -0,0 +1,8 @@ +import OpenAI from 'openai'; + +async function typeTests(client: OpenAI) { + const response = await client.chat.completions.create({ model: 'gpt-4o', messages: [] }).asResponse(); + const url: string = response.url; +} + +export {}; diff --git a/ecosystem-tests/node-ts-esm/iitm.js b/ecosystem-tests/node-ts-esm/iitm.js new file mode 100644 index 000000000..1f818d617 --- /dev/null +++ b/ecosystem-tests/node-ts-esm/iitm.js @@ -0,0 +1,2 @@ +import {register} from 'node:module' +register('import-in-the-middle/hook.mjs', import.meta.url) \ No newline at end of file diff --git a/ecosystem-tests/node-ts-esm/package-lock.json b/ecosystem-tests/node-ts-esm/package-lock.json index cb5b8eaa8..7b167e3e7 100644 --- a/ecosystem-tests/node-ts-esm/package-lock.json +++ b/ecosystem-tests/node-ts-esm/package-lock.json @@ -9,7 +9,7 @@ "version": "0.0.1", "dependencies": { "formdata-node": "^5.0.1", - "node-fetch": "^3.0.0" + "import-in-the-middle": "^1.11.2" }, "devDependencies": { "@types/node": "^20.3.1", @@ -1190,7 +1190,6 @@ "version": "8.10.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", - "dev": true, "bin": { "acorn": "bin/acorn" }, @@ -1198,6 +1197,15 @@ "node": ">=0.4.0" } }, + "node_modules/acorn-import-attributes": { + "version": "1.9.5", + "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", + "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", + "license": "MIT", + "peerDependencies": { + "acorn": "^8" + } + }, "node_modules/acorn-walk": { "version": "8.2.0", "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", @@ -1549,8 +1557,7 @@ "node_modules/cjs-module-lexer": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz", - "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==", - "dev": true + "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==" }, "node_modules/cliui": { "version": "8.0.1", @@ -1653,14 +1660,6 @@ "node": ">= 8" } }, - "node_modules/data-uri-to-buffer": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", - "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", - "engines": { - "node": ">= 12" - } - }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -1864,36 +1863,6 @@ "bser": "2.1.1" } }, - "node_modules/fetch-blob": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", - "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "paypal", - "url": "https://paypal.me/jimmywarting" - } - ], - "dependencies": { - "node-domexception": "^1.0.0", - "web-streams-polyfill": "^3.0.3" - }, - "engines": { - "node": "^12.20 || >= 14.13" - } - }, - "node_modules/fetch-blob/node_modules/web-streams-polyfill": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", - "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", - "engines": { - "node": ">= 8" - } - }, "node_modules/fill-range": { "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", @@ -1931,17 +1900,6 @@ "node": ">= 14.17" } }, - "node_modules/formdata-polyfill": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", - "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", - "dependencies": { - "fetch-blob": "^3.1.2" - }, - "engines": { - "node": ">=12.20.0" - } - }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -2081,6 +2039,18 @@ "node": ">=10.17.0" } }, + "node_modules/import-in-the-middle": { + "version": "1.11.2", + "resolved": "https://registry.npmjs.org/import-in-the-middle/-/import-in-the-middle-1.11.2.tgz", + "integrity": "sha512-gK6Rr6EykBcc6cVWRSBR5TWf8nn6hZMYSRYqCcHa0l0d1fPK7JSYo6+Mlmck76jIX9aL/IZ71c06U2VpFwl1zA==", + "license": "Apache-2.0", + "dependencies": { + "acorn": "^8.8.2", + "acorn-import-attributes": "^1.9.5", + "cjs-module-lexer": "^1.2.2", + "module-details-from-path": "^1.0.3" + } + }, "node_modules/import-local": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", @@ -3078,6 +3048,12 @@ "node": "*" } }, + "node_modules/module-details-from-path": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/module-details-from-path/-/module-details-from-path-1.0.3.tgz", + "integrity": "sha512-ySViT69/76t8VhE1xXHK6Ch4NcDd26gx0MzKXLO+F7NOtnqH68d9zF94nT8ZWSxXh8ELOERsnJO/sWt1xZYw5A==", + "license": "MIT" + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -3108,23 +3084,6 @@ "node": ">=10.5.0" } }, - "node_modules/node-fetch": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", - "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", - "dependencies": { - "data-uri-to-buffer": "^4.0.0", - "fetch-blob": "^3.1.4", - "formdata-polyfill": "^4.0.10" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/node-fetch" - } - }, "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", diff --git a/ecosystem-tests/node-ts-esm/package.json b/ecosystem-tests/node-ts-esm/package.json index a4f42790f..198615c6f 100644 --- a/ecosystem-tests/node-ts-esm/package.json +++ b/ecosystem-tests/node-ts-esm/package.json @@ -6,11 +6,11 @@ "private": true, "scripts": { "tsc": "tsc && tsc -p tsconfig.noderesolution.json", - "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js" + "test": "node --import=./iitm.js --experimental-vm-modules node_modules/jest/bin/jest.js" }, "dependencies": { "formdata-node": "^5.0.1", - "node-fetch": "^3.0.0" + "import-in-the-middle": "^1.11.2" }, "devDependencies": { "@types/node": "^20.3.1", diff --git a/ecosystem-tests/node-ts-esm/tests/shims.ts b/ecosystem-tests/node-ts-esm/tests/shims.ts deleted file mode 100644 index a7a22ddb4..000000000 --- a/ecosystem-tests/node-ts-esm/tests/shims.ts +++ /dev/null @@ -1,7 +0,0 @@ -// shouldn't need extension, but Jest's ESM module resolution is broken -import 'openai/shims/node.mjs'; -import * as shims from 'openai/_shims/index'; - -test('openai/shims/node', () => { - expect(shims.kind).toEqual('node'); -}); diff --git a/ecosystem-tests/node-ts-esm/tests/test-esnext.ts b/ecosystem-tests/node-ts-esm/tests/test-esnext.ts index 05cdd1047..0b34026fa 100644 --- a/ecosystem-tests/node-ts-esm/tests/test-esnext.ts +++ b/ecosystem-tests/node-ts-esm/tests/test-esnext.ts @@ -1,13 +1,12 @@ -import 'openai/shims/node.mjs'; import OpenAI from 'openai'; import { distance } from 'fastest-levenshtein'; import { ChatCompletion } from 'openai/resources/chat/completions'; -import * as shims from 'openai/_shims/index'; // The tests in this file don't typecheck with "moduleResolution": "node" -function typeTests(x: shims.Request) { - const url: string = x.url; +async function typeTests(client: OpenAI) { + const response = await client.chat.completions.create({ model: 'gpt-4o', messages: [] }).asResponse(); + const url: string = response.url; } const client = new OpenAI(); @@ -52,24 +51,15 @@ it(`raw response`, async function () { }) .asResponse(); - // test that we can use node-fetch Response API const chunks: string[] = []; - const { body } = response; - if (!body) throw new Error(`expected response.body to be defined`); - body.on('data', (chunk) => chunks.push(chunk)); - await new Promise((resolve, reject) => { - body.once('end', resolve); - body.once('error', reject); - }); + if (!response.body) throw new Error(`expected response.body to be defined`); + + const decoder = new TextDecoder(); + + for await (const chunk of response.body) { + chunks.push(decoder.decode(chunk)); + } + const json: ChatCompletion = JSON.parse(chunks.join('')); expect(json.choices[0]?.message.content || '').toBeSimilarTo('This is a test', 10); }); - -test('query strings', () => { - expect( - decodeURIComponent((client as any).stringifyQuery({ foo: { nested: { a: true, b: 'foo' } } })), - ).toEqual('foo[nested][a]=true&foo[nested][b]=foo'); - expect( - decodeURIComponent((client as any).stringifyQuery({ foo: { nested: { a: ['hello', 'world'] } } })), - ).toEqual('foo[nested][a][]=hello&foo[nested][a][]=world'); -}); diff --git a/ecosystem-tests/node-ts-esm/tests/test.ts b/ecosystem-tests/node-ts-esm/tests/test.ts index 7694a9874..8bbabca11 100644 --- a/ecosystem-tests/node-ts-esm/tests/test.ts +++ b/ecosystem-tests/node-ts-esm/tests/test.ts @@ -1,8 +1,5 @@ -// shouldn't need extension, but Jest's ESM module resolution is broken -import 'openai/shims/node.mjs'; import OpenAI, { toFile } from 'openai'; import { TranscriptionCreateParams } from 'openai/resources/audio/transcriptions'; -import fetch from 'node-fetch'; import { File as FormDataFile, Blob as FormDataBlob } from 'formdata-node'; import * as fs from 'fs'; import { distance } from 'fastest-levenshtein'; @@ -70,24 +67,20 @@ it(`streaming works`, async function () { expect(chunks.map((c) => c.choices[0]?.delta.content || '').join('')).toBeSimilarTo('This is a test', 10); }); -it('handles formdata-node File', async function () { - const file = await fetch(url) - .then((x) => x.arrayBuffer()) - .then((x) => new FormDataFile([x], filename)); - - const params: TranscriptionCreateParams = { file, model }; - - const result = await client.audio.transcriptions.create(params); - expect(result.text).toBeSimilarTo(correctAnswer, 12); -}); - -// @ts-ignore avoid DOM lib for testing purposes if (typeof File !== 'undefined') { it('handles builtinFile', async function () { const file = await fetch(url) .then((x) => x.arrayBuffer()) - // @ts-ignore avoid DOM lib for testing purposes - .then((x) => new File([x], filename)); + .then( + (x) => + new File( + [ + // @ts-ignore array buffer can't be passed to File at the type-level with certain tsconfigs + x, + ], + filename, + ), + ); const result = await client.audio.transcriptions.create({ file, model }); expect(result.text).toBeSimilarTo(correctAnswer, 12); @@ -114,26 +107,15 @@ const fineTune = `{"prompt": "", "completion": " { it('handles form-data Blob', async function () { const result = await client.files.create({ - file: await toFile( - new FormDataBlob([ - // @ts-ignore avoid DOM lib for testing purposes - new TextEncoder().encode(fineTune), - ]), - 'finetune.jsonl', - ), + file: await toFile(new FormDataBlob([new TextEncoder().encode(fineTune)]), 'finetune.jsonl'), purpose: 'fine-tune', }); expect(result.filename).toEqual('finetune.jsonl'); }); - // @ts-ignore avoid DOM lib for testing purposes if (typeof Blob !== 'undefined') { it('handles builtin Blob', async function () { const result = await client.files.create({ - file: await toFile( - // @ts-ignore avoid DOM lib for testing purposes - new Blob([new TextEncoder().encode(fineTune)]), - 'finetune.jsonl', - ), + file: await toFile(new Blob([new TextEncoder().encode(fineTune)]), 'finetune.jsonl'), purpose: 'fine-tune', }); expect(result.filename).toEqual('finetune.jsonl'); @@ -141,44 +123,36 @@ describe('toFile', () => { } it('handles Uint8Array', async function () { const result = await client.files.create({ - file: await toFile( - // @ts-ignore avoid DOM lib for testing purposes - new TextEncoder().encode(fineTune), - 'finetune.jsonl', - ), + file: await toFile(new TextEncoder().encode(fineTune), 'finetune.jsonl'), purpose: 'fine-tune', }); expect(result.filename).toEqual('finetune.jsonl'); }); it('handles ArrayBuffer', async function () { const result = await client.files.create({ - file: await toFile( - // @ts-ignore avoid DOM lib for testing purposes - new TextEncoder().encode(fineTune).buffer, - 'finetune.jsonl', - ), + file: await toFile(new TextEncoder().encode(fineTune).buffer, 'finetune.jsonl'), purpose: 'fine-tune', }); expect(result.filename).toEqual('finetune.jsonl'); }); it('handles DataView', async function () { const result = await client.files.create({ - file: await toFile( - // @ts-ignore avoid DOM lib for testing purposes - new DataView(new TextEncoder().encode(fineTune).buffer), - 'finetune.jsonl', - ), + file: await toFile(new DataView(new TextEncoder().encode(fineTune).buffer), 'finetune.jsonl'), purpose: 'fine-tune', }); expect(result.filename).toEqual('finetune.jsonl'); }); -}); -test('query strings', () => { - expect( - decodeURIComponent((client as any).stringifyQuery({ foo: { nested: { a: true, b: 'foo' } } })), - ).toEqual('foo[nested][a]=true&foo[nested][b]=foo'); - expect( - decodeURIComponent((client as any).stringifyQuery({ foo: { nested: { a: ['hello', 'world'] } } })), - ).toEqual('foo[nested][a][]=hello&foo[nested][a][]=world'); + it('handles formdata-node File', async function () { + const file = await fetch(url) + .then((x) => x.arrayBuffer()) + .then((x) => toFile(new FormDataFile([x], filename))); + + expect(file.name).toEqual(filename); + + const params: TranscriptionCreateParams = { file, model }; + + const result = await client.audio.transcriptions.create(params); + expect(result.text).toBeSimilarTo(correctAnswer, 12); + }); }); diff --git a/ecosystem-tests/node-ts4.5-jest27/jest.config.cjs b/ecosystem-tests/node-ts4.5-jest28/jest.config.cjs similarity index 100% rename from ecosystem-tests/node-ts4.5-jest27/jest.config.cjs rename to ecosystem-tests/node-ts4.5-jest28/jest.config.cjs diff --git a/ecosystem-tests/node-ts4.5-jest27/package-lock.json b/ecosystem-tests/node-ts4.5-jest28/package-lock.json similarity index 63% rename from ecosystem-tests/node-ts4.5-jest27/package-lock.json rename to ecosystem-tests/node-ts4.5-jest28/package-lock.json index bedd114f8..1944471b4 100644 --- a/ecosystem-tests/node-ts4.5-jest27/package-lock.json +++ b/ecosystem-tests/node-ts4.5-jest28/package-lock.json @@ -9,143 +9,70 @@ "version": "0.0.1", "dependencies": { "formdata-node": "^4.4.1", - "node-fetch": "^2.6.1", "tsconfig-paths": "^4.0.0" }, "devDependencies": { "@types/jest": "27.5.2", "@types/node": "20.11.20", - "@types/node-fetch": "^2.6.1", "@types/ws": "^8.5.4", "fastest-levenshtein": "^1.0.16", - "jest": "27.5.1", - "ts-jest": "27.1.5", + "jest": "28.1.3", + "ts-jest": "^28.0.0", "typescript": "4.5.5" } }, "node_modules/@ampproject/remapping": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", - "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", "dev": true, "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { "node": ">=6.0.0" } }, "node_modules/@babel/code-frame": { - "version": "7.22.13", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", - "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", + "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", "dev": true, "dependencies": { - "@babel/highlight": "^7.22.13", - "chalk": "^2.4.2" + "@babel/highlight": "^7.24.7", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/code-frame/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/code-frame/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/@babel/code-frame/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/code-frame/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/code-frame/node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/@babel/compat-data": { - "version": "7.22.9", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.9.tgz", - "integrity": "sha512-5UamI7xkUcJ3i9qVDS+KFDEK8/7oJ55/sJMB1Ge7IEapr7KfdfV/HErR+koZwOfd+SgtFKOKRhRakdg++DcJpQ==", + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.25.4.tgz", + "integrity": "sha512-+LGRog6RAsCJrrrg/IO6LGmpphNe5DiK30dGjCoxxeGv49B10/3XYGxPsAwrDlMFcFEvdAUavDT8r9k/hSyQqQ==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.22.17", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.17.tgz", - "integrity": "sha512-2EENLmhpwplDux5PSsZnSbnSkB3tZ6QTksgO25xwEL7pIDcNOMhF5v/s6RzwjMZzZzw9Ofc30gHv5ChCC8pifQ==", + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.25.2.tgz", + "integrity": "sha512-BBt3opiCOxUr9euZ5/ro/Xv8/V7yJ5bjYMqG/C1YAo8MIKAnumZalCN+msbci3Pigy4lIQfPUpfMM27HMGaYEA==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.22.13", - "@babel/generator": "^7.22.15", - "@babel/helper-compilation-targets": "^7.22.15", - "@babel/helper-module-transforms": "^7.22.17", - "@babel/helpers": "^7.22.15", - "@babel/parser": "^7.22.16", - "@babel/template": "^7.22.15", - "@babel/traverse": "^7.22.17", - "@babel/types": "^7.22.17", - "convert-source-map": "^1.7.0", + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.25.0", + "@babel/helper-compilation-targets": "^7.25.2", + "@babel/helper-module-transforms": "^7.25.2", + "@babel/helpers": "^7.25.0", + "@babel/parser": "^7.25.0", + "@babel/template": "^7.25.0", + "@babel/traverse": "^7.25.2", + "@babel/types": "^7.25.2", + "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", "json5": "^2.2.3", @@ -159,15 +86,21 @@ "url": "https://opencollective.com/babel" } }, + "node_modules/@babel/core/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, "node_modules/@babel/generator": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.15.tgz", - "integrity": "sha512-Zu9oWARBqeVOW0dZOjXc3JObrzuqothQ3y/n1kUtrjCoCPLkXUwMvOo/F/TCfoHMbWIFlWwpZtkZVb9ga4U2pA==", + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.25.6.tgz", + "integrity": "sha512-VPC82gr1seXOpkjAAKoLhP50vx4vGNlF4msF64dSFq1P8RfB+QAuJWGHPXXPc8QyfVWwwB/TNNU4+ayZmHNbZw==", "dev": true, "dependencies": { - "@babel/types": "^7.22.15", - "@jridgewell/gen-mapping": "^0.3.2", - "@jridgewell/trace-mapping": "^0.3.17", + "@babel/types": "^7.25.6", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", "jsesc": "^2.5.1" }, "engines": { @@ -175,14 +108,14 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.15.tgz", - "integrity": "sha512-y6EEzULok0Qvz8yyLkCvVX+02ic+By2UdOhylwUOvOn9dvYc9mKICJuuU1n1XBI02YWsNsnrY1kc6DVbjcXbtw==", + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.25.2.tgz", + "integrity": "sha512-U2U5LsSaZ7TAt3cfaymQ8WHh0pxvdHoEk6HVpaexxixjyEquMh0L0YNJNM6CTGKMXV1iksi0iZkGw4AcFkPaaw==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.22.9", - "@babel/helper-validator-option": "^7.22.15", - "browserslist": "^4.21.9", + "@babel/compat-data": "^7.25.2", + "@babel/helper-validator-option": "^7.24.8", + "browserslist": "^4.23.1", "lru-cache": "^5.1.1", "semver": "^6.3.1" }, @@ -190,63 +123,29 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.5.tgz", - "integrity": "sha512-XGmhECfVA/5sAt+H+xpSg0mfrHq6FzNr9Oxh7PSEBBRUb/mL7Kz3NICXb194rCqAEdxkhPT1a88teizAFyvk8Q==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.22.5.tgz", - "integrity": "sha512-wtHSq6jMRE3uF2otvfuD3DIvVhOsSNshQl0Qrd7qC9oQJzHvOL4qQXlQn2916+CXGywIjpGuIkoyZRRxHPiNQQ==", - "dev": true, - "dependencies": { - "@babel/template": "^7.22.5", - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", - "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, "node_modules/@babel/helper-module-imports": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", - "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", + "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", "dev": true, "dependencies": { - "@babel/types": "^7.22.15" + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.22.17", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.17.tgz", - "integrity": "sha512-XouDDhQESrLHTpnBtCKExJdyY4gJCdrvH2Pyv8r8kovX2U8G0dRUOT45T9XlbLtuu9CLXP15eusnkprhoPV5iQ==", + "version": "7.25.2", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.25.2.tgz", + "integrity": "sha512-BjyRAbix6j/wv83ftcVJmBt72QtHI56C7JXZoG2xATiLpmoC7dpd8WnkikExHDVPpi/3qCmO6WY1EaXOluiecQ==", "dev": true, "dependencies": { - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-module-imports": "^7.22.15", - "@babel/helper-simple-access": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/helper-validator-identifier": "^7.22.15" + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-simple-access": "^7.24.7", + "@babel/helper-validator-identifier": "^7.24.7", + "@babel/traverse": "^7.25.2" }, "engines": { "node": ">=6.9.0" @@ -256,88 +155,77 @@ } }, "node_modules/@babel/helper-plugin-utils": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", - "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz", + "integrity": "sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-simple-access": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", - "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", + "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", "dev": true, "dependencies": { - "@babel/types": "^7.22.5" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.22.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", - "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", - "dev": true, - "dependencies": { - "@babel/types": "^7.22.5" + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", - "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz", + "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.15.tgz", - "integrity": "sha512-4E/F9IIEi8WR94324mbDUMo074YTheJmd7eZF5vITTeYchqAi6sYXRLHUVsmkdmY4QjfKTcB2jB7dVP3NaBElQ==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", + "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.15.tgz", - "integrity": "sha512-bMn7RmyFjY/mdECUbgn9eoSY4vqvacUnS9i9vGAGttgFWesO6B4CYWA7XlpbWgBt71iv/hfbPlynohStqnu5hA==", + "version": "7.24.8", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz", + "integrity": "sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helpers": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.15.tgz", - "integrity": "sha512-7pAjK0aSdxOwR+CcYAqgWOGy5dcfvzsTIfFTb2odQqW47MDfv14UaJDY6eng8ylM2EaeKXdxaSWESbkmaQHTmw==", + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.6.tgz", + "integrity": "sha512-Xg0tn4HcfTijTwfDwYlvVCl43V6h4KyVVX2aEm4qdO/PC6L2YvzLHFdmxhoeSA3eslcE6+ZVXHgWwopXYLNq4Q==", "dev": true, "dependencies": { - "@babel/template": "^7.22.15", - "@babel/traverse": "^7.22.15", - "@babel/types": "^7.22.15" + "@babel/template": "^7.25.0", + "@babel/types": "^7.25.6" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.22.13", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.13.tgz", - "integrity": "sha512-C/BaXcnnvBCmHTpz/VGZ8jgtE2aYlW4hxDhseJAWZb7gqGM/qtCK6iZUb0TyKFf7BOUsBH7Q7fkRsDRhg1XklQ==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", + "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.22.5", + "@babel/helper-validator-identifier": "^7.24.7", "chalk": "^2.4.2", - "js-tokens": "^4.0.0" + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" }, "engines": { "node": ">=6.9.0" @@ -415,10 +303,13 @@ } }, "node_modules/@babel/parser": { - "version": "7.22.16", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.16.tgz", - "integrity": "sha512-+gPfKv8UWeKKeJTUxe59+OobVcrYHETCsORl61EmSkmgymguYk/X5bp7GuUIXaFsc6y++v8ZxPsLSSuujqDphA==", + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.25.6.tgz", + "integrity": "sha512-trGdfBdbD0l1ZPmcJ83eNxB9rbEax4ALFTF7fN386TMYbeCQbyme5cOEXQhbGXKebwGaB/J52w1mrklMcbgy6Q==", "dev": true, + "dependencies": { + "@babel/types": "^7.25.6" + }, "bin": { "parser": "bin/babel-parser.js" }, @@ -462,6 +353,36 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.25.6.tgz", + "integrity": "sha512-sXaDXaJN9SNLymBdlWFA+bjzBhFD617ZaFiY13dGt7TVslVvVgA6fkZOP7Ki3IGElC45lwHdOTrCtKZGVAWeLQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.8" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/plugin-syntax-import-meta": { "version": "7.10.4", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", @@ -558,6 +479,21 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, "node_modules/@babel/plugin-syntax-top-level-await": { "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", @@ -574,12 +510,12 @@ } }, "node_modules/@babel/plugin-syntax-typescript": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.22.5.tgz", - "integrity": "sha512-1mS2o03i7t1c6VzH6fdQ3OA8tcEIxwG18zIPRp+UY1Ihv6W+XZzBCVxExF9upussPXJ0xE9XRHwMoNs1ep/nRQ==", + "version": "7.25.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.25.4.tgz", + "integrity": "sha512-uMOCoHVU52BsSWxPOMVv5qKRdeSlPuImUCB2dlPuBSU+W2/ROE7/Zg8F2Kepbk+8yBa68LlRKxO+xgEVWorsDg==", "dev": true, "dependencies": { - "@babel/helper-plugin-utils": "^7.22.5" + "@babel/helper-plugin-utils": "^7.24.8" }, "engines": { "node": ">=6.9.0" @@ -589,34 +525,31 @@ } }, "node_modules/@babel/template": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", - "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "version": "7.25.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.0.tgz", + "integrity": "sha512-aOOgh1/5XzKvg1jvVz7AVrx2piJ2XBi227DHmbY6y+bM9H2FlN+IfecYu4Xl0cNiiVejlsCri89LUsbj8vJD9Q==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/parser": "^7.22.15", - "@babel/types": "^7.22.15" + "@babel/code-frame": "^7.24.7", + "@babel/parser": "^7.25.0", + "@babel/types": "^7.25.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.22.17", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.17.tgz", - "integrity": "sha512-xK4Uwm0JnAMvxYZxOVecss85WxTEIbTa7bnGyf/+EgCL5Zt3U7htUpEOWv9detPlamGKuRzCqw74xVglDWpPdg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.22.13", - "@babel/generator": "^7.22.15", - "@babel/helper-environment-visitor": "^7.22.5", - "@babel/helper-function-name": "^7.22.5", - "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.22.16", - "@babel/types": "^7.22.17", - "debug": "^4.1.0", + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.25.6.tgz", + "integrity": "sha512-9Vrcx5ZW6UwK5tvqsj0nGpp/XzqthkT0dqIc9g1AdtygFToNtTF67XzYS//dm+SAK9cp3B9R4ZO/46p63SCjlQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.25.6", + "@babel/parser": "^7.25.6", + "@babel/template": "^7.25.0", + "@babel/types": "^7.25.6", + "debug": "^4.3.1", "globals": "^11.1.0" }, "engines": { @@ -624,13 +557,13 @@ } }, "node_modules/@babel/types": { - "version": "7.22.17", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.17.tgz", - "integrity": "sha512-YSQPHLFtQNE5xN9tHuZnzu8vPr61wVTBZdfv1meex1NBosa4iT05k/Jw06ddJugi4bk7The/oSwQGFcksmEJQg==", + "version": "7.25.6", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.25.6.tgz", + "integrity": "sha512-/l42B1qxpG6RdfYf343Uw1vmDjeNhneUXtzhojE7pDgfpEypmRhI6j1kr17XCVv4Cgl9HdAiQY2x0GwKm7rWCw==", "dev": true, "dependencies": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.15", + "@babel/helper-string-parser": "^7.24.8", + "@babel/helper-validator-identifier": "^7.24.7", "to-fast-properties": "^2.0.0" }, "engines": { @@ -669,59 +602,60 @@ } }, "node_modules/@jest/console": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-27.5.1.tgz", - "integrity": "sha512-kZ/tNpS3NXn0mlXXXPNuDZnb4c0oZ20r4K5eemM2k30ZC3G0T02nXUvyhf5YdbXWHPEJLc9qGLxEZ216MdL+Zg==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-28.1.3.tgz", + "integrity": "sha512-QPAkP5EwKdK/bxIr6C1I4Vs0rm2nHiANzj/Z5X2JQkrZo6IqvC4ldZ9K95tF0HdidhA8Bo6egxSzUFPYKcEXLw==", "dev": true, "dependencies": { - "@jest/types": "^27.5.1", + "@jest/types": "^28.1.3", "@types/node": "*", "chalk": "^4.0.0", - "jest-message-util": "^27.5.1", - "jest-util": "^27.5.1", + "jest-message-util": "^28.1.3", + "jest-util": "^28.1.3", "slash": "^3.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, "node_modules/@jest/core": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-27.5.1.tgz", - "integrity": "sha512-AK6/UTrvQD0Cd24NSqmIA6rKsu0tKIxfiCducZvqxYdmMisOYAsdItspT+fQDQYARPf8XgjAFZi0ogW2agH5nQ==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-28.1.3.tgz", + "integrity": "sha512-CIKBrlaKOzA7YG19BEqCw3SLIsEwjZkeJzf5bdooVnW4bH5cktqe3JX+G2YV1aK5vP8N9na1IGWFzYaTp6k6NA==", "dev": true, "dependencies": { - "@jest/console": "^27.5.1", - "@jest/reporters": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", + "@jest/console": "^28.1.3", + "@jest/reporters": "^28.1.3", + "@jest/test-result": "^28.1.3", + "@jest/transform": "^28.1.3", + "@jest/types": "^28.1.3", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", - "emittery": "^0.8.1", + "ci-info": "^3.2.0", "exit": "^0.1.2", "graceful-fs": "^4.2.9", - "jest-changed-files": "^27.5.1", - "jest-config": "^27.5.1", - "jest-haste-map": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-regex-util": "^27.5.1", - "jest-resolve": "^27.5.1", - "jest-resolve-dependencies": "^27.5.1", - "jest-runner": "^27.5.1", - "jest-runtime": "^27.5.1", - "jest-snapshot": "^27.5.1", - "jest-util": "^27.5.1", - "jest-validate": "^27.5.1", - "jest-watcher": "^27.5.1", + "jest-changed-files": "^28.1.3", + "jest-config": "^28.1.3", + "jest-haste-map": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-regex-util": "^28.0.2", + "jest-resolve": "^28.1.3", + "jest-resolve-dependencies": "^28.1.3", + "jest-runner": "^28.1.3", + "jest-runtime": "^28.1.3", + "jest-snapshot": "^28.1.3", + "jest-util": "^28.1.3", + "jest-validate": "^28.1.3", + "jest-watcher": "^28.1.3", "micromatch": "^4.0.4", + "pretty-format": "^28.1.3", "rimraf": "^3.0.0", "slash": "^3.0.0", "strip-ansi": "^6.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" }, "peerDependencies": { "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" @@ -732,86 +666,153 @@ } } }, + "node_modules/@jest/core/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/core/node_modules/pretty-format": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.3.tgz", + "integrity": "sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==", + "dev": true, + "dependencies": { + "@jest/schemas": "^28.1.3", + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/core/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true + }, "node_modules/@jest/environment": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-27.5.1.tgz", - "integrity": "sha512-/WQjhPJe3/ghaol/4Bq480JKXV/Rfw8nQdN7f41fM8VDHLcxKXou6QyXAh3EFr9/bVG3x74z1NWDkP87EiY8gA==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-28.1.3.tgz", + "integrity": "sha512-1bf40cMFTEkKyEf585R9Iz1WayDjHoHqvts0XFYEqyKM3cFWDpeMoqKKTAF9LSYQModPUlh8FKptoM2YcMWAXA==", "dev": true, "dependencies": { - "@jest/fake-timers": "^27.5.1", - "@jest/types": "^27.5.1", + "@jest/fake-timers": "^28.1.3", + "@jest/types": "^28.1.3", "@types/node": "*", - "jest-mock": "^27.5.1" + "jest-mock": "^28.1.3" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/expect": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-28.1.3.tgz", + "integrity": "sha512-lzc8CpUbSoE4dqT0U+g1qODQjBRHPpCPXissXD4mS9+sWQdmmpeJ9zSH1rS1HEkrsMN0fb7nKrJ9giAR1d3wBw==", + "dev": true, + "dependencies": { + "expect": "^28.1.3", + "jest-snapshot": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-28.1.3.tgz", + "integrity": "sha512-wvbi9LUrHJLn3NlDW6wF2hvIMtd4JUl2QNVrjq+IBSHirgfrR3o9RnVtxzdEGO2n9JyIWwHnLfby5KzqBGg2YA==", + "dev": true, + "dependencies": { + "jest-get-type": "^28.0.2" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/@jest/expect-utils/node_modules/jest-get-type": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", + "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, "node_modules/@jest/fake-timers": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.5.1.tgz", - "integrity": "sha512-/aPowoolwa07k7/oM3aASneNeBGCmGQsc3ugN4u6s4C/+s5M64MFo/+djTdiwcbQlRfFElGuDXWzaWj6QgKObQ==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-28.1.3.tgz", + "integrity": "sha512-D/wOkL2POHv52h+ok5Oj/1gOG9HSywdoPtFsRCUmlCILXNn5eIWmcnd3DIiWlJnpGvQtmajqBP95Ei0EimxfLw==", "dev": true, "dependencies": { - "@jest/types": "^27.5.1", - "@sinonjs/fake-timers": "^8.0.1", + "@jest/types": "^28.1.3", + "@sinonjs/fake-timers": "^9.1.2", "@types/node": "*", - "jest-message-util": "^27.5.1", - "jest-mock": "^27.5.1", - "jest-util": "^27.5.1" + "jest-message-util": "^28.1.3", + "jest-mock": "^28.1.3", + "jest-util": "^28.1.3" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, "node_modules/@jest/globals": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-27.5.1.tgz", - "integrity": "sha512-ZEJNB41OBQQgGzgyInAv0UUfDDj3upmHydjieSxFvTRuZElrx7tXg/uVQ5hYVEwiXs3+aMsAeEc9X7xiSKCm4Q==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-28.1.3.tgz", + "integrity": "sha512-XFU4P4phyryCXu1pbcqMO0GSQcYe1IsalYCDzRNyhetyeyxMcIxa11qPNDpVNLeretItNqEmYYQn1UYz/5x1NA==", "dev": true, "dependencies": { - "@jest/environment": "^27.5.1", - "@jest/types": "^27.5.1", - "expect": "^27.5.1" + "@jest/environment": "^28.1.3", + "@jest/expect": "^28.1.3", + "@jest/types": "^28.1.3" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, "node_modules/@jest/reporters": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-27.5.1.tgz", - "integrity": "sha512-cPXh9hWIlVJMQkVk84aIvXuBB4uQQmFqZiacloFuGiP3ah1sbCxCosidXFDfqG8+6fO1oR2dTJTlsOy4VFmUfw==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-28.1.3.tgz", + "integrity": "sha512-JuAy7wkxQZVNU/V6g9xKzCGC5LVXx9FDcABKsSXp5MiKPEE2144a/vXTEDoyzjUpZKfVwp08Wqg5A4WfTMAzjg==", "dev": true, "dependencies": { "@bcoe/v8-coverage": "^0.2.3", - "@jest/console": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", + "@jest/console": "^28.1.3", + "@jest/test-result": "^28.1.3", + "@jest/transform": "^28.1.3", + "@jest/types": "^28.1.3", + "@jridgewell/trace-mapping": "^0.3.13", "@types/node": "*", "chalk": "^4.0.0", "collect-v8-coverage": "^1.0.0", "exit": "^0.1.2", - "glob": "^7.1.2", + "glob": "^7.1.3", "graceful-fs": "^4.2.9", "istanbul-lib-coverage": "^3.0.0", "istanbul-lib-instrument": "^5.1.0", "istanbul-lib-report": "^3.0.0", "istanbul-lib-source-maps": "^4.0.0", "istanbul-reports": "^3.1.3", - "jest-haste-map": "^27.5.1", - "jest-resolve": "^27.5.1", - "jest-util": "^27.5.1", - "jest-worker": "^27.5.1", + "jest-message-util": "^28.1.3", + "jest-util": "^28.1.3", + "jest-worker": "^28.1.3", "slash": "^3.0.0", - "source-map": "^0.6.0", "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", "terminal-link": "^2.0.0", - "v8-to-istanbul": "^8.1.0" + "v8-to-istanbul": "^9.0.1" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" }, "peerDependencies": { "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" @@ -822,140 +823,159 @@ } } }, + "node_modules/@jest/schemas": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-28.1.3.tgz", + "integrity": "sha512-/l/VWsdt/aBXgjshLWOFyFt3IVdYypu5y2Wn2rOO1un6nkqIn8SLXzgIMYXFyYsRWDyF5EthmKJMIdJvk08grg==", + "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.24.1" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, "node_modules/@jest/source-map": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-27.5.1.tgz", - "integrity": "sha512-y9NIHUYF3PJRlHk98NdC/N1gl88BL08aQQgu4k4ZopQkCw9t9cV8mtl3TV8b/YCB8XaVTFrmUTAJvjsntDireg==", + "version": "28.1.2", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-28.1.2.tgz", + "integrity": "sha512-cV8Lx3BeStJb8ipPHnqVw/IM2VCMWO3crWZzYodSIkxXnRcXJipCdx1JCK0K5MsJJouZQTH73mzf4vgxRaH9ww==", "dev": true, "dependencies": { + "@jridgewell/trace-mapping": "^0.3.13", "callsites": "^3.0.0", - "graceful-fs": "^4.2.9", - "source-map": "^0.6.0" + "graceful-fs": "^4.2.9" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, "node_modules/@jest/test-result": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-27.5.1.tgz", - "integrity": "sha512-EW35l2RYFUcUQxFJz5Cv5MTOxlJIQs4I7gxzi2zVU7PJhOwfYq1MdC5nhSmYjX1gmMmLPvB3sIaC+BkcHRBfag==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-28.1.3.tgz", + "integrity": "sha512-kZAkxnSE+FqE8YjW8gNuoVkkC9I7S1qmenl8sGcDOLropASP+BkcGKwhXoyqQuGOGeYY0y/ixjrd/iERpEXHNg==", "dev": true, "dependencies": { - "@jest/console": "^27.5.1", - "@jest/types": "^27.5.1", + "@jest/console": "^28.1.3", + "@jest/types": "^28.1.3", "@types/istanbul-lib-coverage": "^2.0.0", "collect-v8-coverage": "^1.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, "node_modules/@jest/test-sequencer": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.5.1.tgz", - "integrity": "sha512-LCheJF7WB2+9JuCS7VB/EmGIdQuhtqjRNI9A43idHv3E4KltCTsPsLxvdaubFHSYwY/fNjMWjl6vNRhDiN7vpQ==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-28.1.3.tgz", + "integrity": "sha512-NIMPEqqa59MWnDi1kvXXpYbqsfQmSJsIbnd85mdVGkiDfQ9WQQTXOLsvISUfonmnBT+w85WEgneCigEEdHDFxw==", "dev": true, "dependencies": { - "@jest/test-result": "^27.5.1", + "@jest/test-result": "^28.1.3", "graceful-fs": "^4.2.9", - "jest-haste-map": "^27.5.1", - "jest-runtime": "^27.5.1" + "jest-haste-map": "^28.1.3", + "slash": "^3.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, "node_modules/@jest/transform": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-27.5.1.tgz", - "integrity": "sha512-ipON6WtYgl/1329g5AIJVbUuEh0wZVbdpGwC99Jw4LwuoBNS95MVphU6zOeD9pDkon+LLbFL7lOQRapbB8SCHw==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-28.1.3.tgz", + "integrity": "sha512-u5dT5di+oFI6hfcLOHGTAfmUxFRrjK+vnaP0kkVow9Md/M7V/MxqQMOz/VV25UZO8pzeA9PjfTpOu6BDuwSPQA==", "dev": true, "dependencies": { - "@babel/core": "^7.1.0", - "@jest/types": "^27.5.1", + "@babel/core": "^7.11.6", + "@jest/types": "^28.1.3", + "@jridgewell/trace-mapping": "^0.3.13", "babel-plugin-istanbul": "^6.1.1", "chalk": "^4.0.0", "convert-source-map": "^1.4.0", "fast-json-stable-stringify": "^2.0.0", "graceful-fs": "^4.2.9", - "jest-haste-map": "^27.5.1", - "jest-regex-util": "^27.5.1", - "jest-util": "^27.5.1", + "jest-haste-map": "^28.1.3", + "jest-regex-util": "^28.0.2", + "jest-util": "^28.1.3", "micromatch": "^4.0.4", "pirates": "^4.0.4", "slash": "^3.0.0", - "source-map": "^0.6.1", - "write-file-atomic": "^3.0.0" + "write-file-atomic": "^4.0.1" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, "node_modules/@jest/types": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-27.5.1.tgz", - "integrity": "sha512-Cx46iJ9QpwQTjIdq5VJu2QTMMs3QlEjI0x1QbBP5W1+nMzyc2XmimiRR/CbX9TO0cPTeUlxWMOu8mslYsJ8DEw==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-28.1.3.tgz", + "integrity": "sha512-RyjiyMUZrKz/c+zlMFO1pm70DcIlST8AeWTkoUdZevew44wcNZQHsEVOiCVtgVnlFFD82FPaXycys58cf2muVQ==", "dev": true, "dependencies": { + "@jest/schemas": "^28.1.3", "@types/istanbul-lib-coverage": "^2.0.0", "@types/istanbul-reports": "^3.0.0", "@types/node": "*", - "@types/yargs": "^16.0.0", + "@types/yargs": "^17.0.8", "chalk": "^4.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", "dev": true, "dependencies": { - "@jridgewell/set-array": "^1.0.1", + "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" + "@jridgewell/trace-mapping": "^0.3.24" }, "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", - "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", "dev": true, "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", "dev": true, "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", "dev": true }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.19", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz", - "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==", + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@sinclair/typebox": { + "version": "0.24.51", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.24.51.tgz", + "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==", + "dev": true + }, "node_modules/@sinonjs/commons": { "version": "1.8.6", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz", @@ -966,27 +986,18 @@ } }, "node_modules/@sinonjs/fake-timers": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz", - "integrity": "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==", + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz", + "integrity": "sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw==", "dev": true, "dependencies": { "@sinonjs/commons": "^1.7.0" } }, - "node_modules/@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, "node_modules/@types/babel__core": { - "version": "7.20.1", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.1.tgz", - "integrity": "sha512-aACu/U/omhdk15O4Nfb+fHgH/z3QsfQzpnvRZhYhThms83ZnAOZz7zZAWO7mn2yyNQaA4xTO8GLK3uqFU4bYYw==", + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", "dev": true, "dependencies": { "@babel/parser": "^7.20.7", @@ -997,18 +1008,18 @@ } }, "node_modules/@types/babel__generator": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", - "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", + "version": "7.6.8", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", + "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", "dev": true, "dependencies": { "@babel/types": "^7.0.0" } }, "node_modules/@types/babel__template": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", - "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", "dev": true, "dependencies": { "@babel/parser": "^7.1.0", @@ -1016,42 +1027,42 @@ } }, "node_modules/@types/babel__traverse": { - "version": "7.20.1", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.1.tgz", - "integrity": "sha512-MitHFXnhtgwsGZWtT68URpOvLN4EREih1u3QtQiN4VdAxWKRVvGCSvw/Qth0M0Qq3pJpnGOu5JaM/ydK7OGbqg==", + "version": "7.20.6", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.6.tgz", + "integrity": "sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==", "dev": true, "dependencies": { "@babel/types": "^7.20.7" } }, "node_modules/@types/graceful-fs": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz", - "integrity": "sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==", + "version": "4.1.9", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.9.tgz", + "integrity": "sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==", "dev": true, "dependencies": { "@types/node": "*" } }, "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", - "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", "dev": true }, "node_modules/@types/istanbul-lib-report": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", - "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", "dev": true, "dependencies": { "@types/istanbul-lib-coverage": "*" } }, "node_modules/@types/istanbul-reports": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", - "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", "dev": true, "dependencies": { "@types/istanbul-lib-report": "*" @@ -1076,16 +1087,6 @@ "undici-types": "~5.26.4" } }, - "node_modules/@types/node-fetch": { - "version": "2.6.11", - "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.11.tgz", - "integrity": "sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==", - "dev": true, - "dependencies": { - "@types/node": "*", - "form-data": "^4.0.0" - } - }, "node_modules/@types/prettier": { "version": "2.7.3", "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.3.tgz", @@ -1093,9 +1094,9 @@ "dev": true }, "node_modules/@types/stack-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", - "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", + "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", "dev": true }, "node_modules/@types/ws": { @@ -1108,103 +1109,42 @@ } }, "node_modules/@types/yargs": { - "version": "16.0.5", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.5.tgz", - "integrity": "sha512-AxO/ADJOBFJScHbWhq2xAhlWP24rY4aCEG/NFaMvbT3X2MgRsLjhjQwsn0Zi5zn0LG9jUhCCZMeX9Dkuw6k+vQ==", + "version": "17.0.33", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", + "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", "dev": true, "dependencies": { "@types/yargs-parser": "*" } }, "node_modules/@types/yargs-parser": { - "version": "21.0.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", - "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", - "dev": true - }, - "node_modules/abab": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.6.tgz", - "integrity": "sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==", + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", "dev": true }, - "node_modules/acorn": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", - "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", "dev": true, - "bin": { - "acorn": "bin/acorn" + "dependencies": { + "type-fest": "^0.21.3" }, "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-globals": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz", - "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==", - "dev": true, - "dependencies": { - "acorn": "^7.1.1", - "acorn-walk": "^7.1.1" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/acorn-globals/node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, - "bin": { - "acorn": "bin/acorn" - }, "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-walk": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", - "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.21.3" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" + "node": ">=8" } }, "node_modules/ansi-styles": { @@ -1244,29 +1184,22 @@ "sprintf-js": "~1.0.2" } }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true - }, "node_modules/babel-jest": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-27.5.1.tgz", - "integrity": "sha512-cdQ5dXjGRd0IBRATiQ4mZGlGlRE8kJpjPOixdNRdT+m3UcNqmYWN6rK6nvtXYfY3D76cb8s/O1Ss8ea24PIwcg==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-28.1.3.tgz", + "integrity": "sha512-epUaPOEWMk3cWX0M/sPvCHHCe9fMFAa/9hXEgKP8nFfNl/jlGkE9ucq9NqkZGXLDduCJYS0UvSlPUwC0S+rH6Q==", "dev": true, "dependencies": { - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", + "@jest/transform": "^28.1.3", "@types/babel__core": "^7.1.14", "babel-plugin-istanbul": "^6.1.1", - "babel-preset-jest": "^27.5.1", + "babel-preset-jest": "^28.1.3", "chalk": "^4.0.0", "graceful-fs": "^4.2.9", "slash": "^3.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" }, "peerDependencies": { "@babel/core": "^7.8.0" @@ -1289,54 +1222,57 @@ } }, "node_modules/babel-plugin-jest-hoist": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.5.1.tgz", - "integrity": "sha512-50wCwD5EMNW4aRpOwtqzyZHIewTYNxLA4nhB+09d8BIssfNfzBRhkBIHiaPv1Si226TQSvp8gxAJm2iY2qs2hQ==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-28.1.3.tgz", + "integrity": "sha512-Ys3tUKAmfnkRUpPdpa98eYrAR0nV+sSFUZZEGuQ2EbFd1y4SOLtD5QDNHAq+bb9a+bbXvYQC4b+ID/THIMcU6Q==", "dev": true, "dependencies": { "@babel/template": "^7.3.3", "@babel/types": "^7.3.3", - "@types/babel__core": "^7.0.0", + "@types/babel__core": "^7.1.14", "@types/babel__traverse": "^7.0.6" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, "node_modules/babel-preset-current-node-syntax": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", - "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.1.0.tgz", + "integrity": "sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw==", "dev": true, "dependencies": { "@babel/plugin-syntax-async-generators": "^7.8.4", "@babel/plugin-syntax-bigint": "^7.8.3", - "@babel/plugin-syntax-class-properties": "^7.8.3", - "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-import-attributes": "^7.24.7", + "@babel/plugin-syntax-import-meta": "^7.10.4", "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", "@babel/plugin-syntax-object-rest-spread": "^7.8.3", "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-top-level-await": "^7.8.3" + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5" }, "peerDependencies": { "@babel/core": "^7.0.0" } }, "node_modules/babel-preset-jest": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.5.1.tgz", - "integrity": "sha512-Nptf2FzlPCWYuJg41HBqXVT8ym6bXOevuCTbhxlUpjwtysGaIWFvDEjp4y+G7fl13FgOdjs7P/DmErqH7da0Ag==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-28.1.3.tgz", + "integrity": "sha512-L+fupJvlWAHbQfn74coNX3zf60LXMJsezNvvx8eIh7iOR1luJ1poxYgQk1F8PYtNq/6QODDHCqsSnTFSWC491A==", "dev": true, "dependencies": { - "babel-plugin-jest-hoist": "^27.5.1", + "babel-plugin-jest-hoist": "^28.1.3", "babel-preset-current-node-syntax": "^1.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" }, "peerDependencies": { "@babel/core": "^7.0.0" @@ -1359,27 +1295,21 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" } }, - "node_modules/browser-process-hrtime": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz", - "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==", - "dev": true - }, "node_modules/browserslist": { - "version": "4.21.10", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz", - "integrity": "sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.0.tgz", + "integrity": "sha512-Rmb62sR1Zpjql25eSanFGEhAxcFwfA1K0GuQcLoaJBAcENegrQut3hYdhXFF1obQfiDyqIW/cLM5HSJ/9k884A==", "dev": true, "funding": [ { @@ -1396,10 +1326,10 @@ } ], "dependencies": { - "caniuse-lite": "^1.0.30001517", - "electron-to-chromium": "^1.4.477", - "node-releases": "^2.0.13", - "update-browserslist-db": "^1.0.11" + "caniuse-lite": "^1.0.30001663", + "electron-to-chromium": "^1.5.28", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.0" }, "bin": { "browserslist": "cli.js" @@ -1454,9 +1384,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001534", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001534.tgz", - "integrity": "sha512-vlPVrhsCS7XaSh2VvWluIQEzVhefrUQcEsQWSS5A5V+dM07uv1qHeQzAOTGIMy9i3e9bH15+muvI/UHojVgS/Q==", + "version": "1.0.30001663", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001663.tgz", + "integrity": "sha512-o9C3X27GLKbLeTYZ6HBOLU1tsAcBZsLis28wrVzddShCS16RujjHp9GDHKZqrB3meE0YjhawvMFsGb/igqiPzA==", "dev": true, "funding": [ { @@ -1499,9 +1429,9 @@ } }, "node_modules/ci-info": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", - "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", "dev": true, "funding": [ { @@ -1514,20 +1444,23 @@ } }, "node_modules/cjs-module-lexer": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz", - "integrity": "sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.1.tgz", + "integrity": "sha512-cuSVIHi9/9E/+821Qjdvngor+xpnlwnuwIyZOaLmHBVdXL+gP+I6QQB9VkO7RI77YIcTV+S1W9AreJ5eN63JBA==", "dev": true }, "node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, "dependencies": { "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", + "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" } }, "node_modules/co": { @@ -1564,18 +1497,6 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -1602,51 +1523,13 @@ "node": ">= 8" } }, - "node_modules/cssom": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz", - "integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==", - "dev": true - }, - "node_modules/cssstyle": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz", - "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==", - "dev": true, - "dependencies": { - "cssom": "~0.3.6" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cssstyle/node_modules/cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", - "dev": true - }, - "node_modules/data-urls": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz", - "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==", - "dev": true, - "dependencies": { - "abab": "^2.0.3", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", "dev": true, "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -1657,12 +1540,6 @@ } } }, - "node_modules/decimal.js": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", - "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==", - "dev": true - }, "node_modules/dedent": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", @@ -1678,15 +1555,6 @@ "node": ">=0.10.0" } }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/detect-newline": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", @@ -1705,40 +1573,19 @@ "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/domexception": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz", - "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==", - "dev": true, - "dependencies": { - "webidl-conversions": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/domexception/node_modules/webidl-conversions": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz", - "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/electron-to-chromium": { - "version": "1.4.520", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.520.tgz", - "integrity": "sha512-Frfus2VpYADsrh1lB3v/ft/WVFlVzOIm+Q0p7U7VqHI6qr7NWHYKe+Wif3W50n7JAFoBsWVsoU0+qDks6WQ60g==", + "version": "1.5.28", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.28.tgz", + "integrity": "sha512-VufdJl+rzaKZoYVUijN13QcXVF5dWPZANeFTLNy+OSpHdDL5ynXTF35+60RSBbaQYB1ae723lQXHCrf4pyLsMw==", "dev": true }, "node_modules/emittery": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz", - "integrity": "sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg==", + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.10.2.tgz", + "integrity": "sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw==", "dev": true, "engines": { - "node": ">=10" + "node": ">=12" }, "funding": { "url": "https://github.com/sindresorhus/emittery?sponsor=1" @@ -1760,9 +1607,9 @@ } }, "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "dev": true, "engines": { "node": ">=6" @@ -1777,27 +1624,6 @@ "node": ">=8" } }, - "node_modules/escodegen": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", - "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", - "dev": true, - "dependencies": { - "esprima": "^4.0.1", - "estraverse": "^5.2.0", - "esutils": "^2.0.2" - }, - "bin": { - "escodegen": "bin/escodegen.js", - "esgenerate": "bin/esgenerate.js" - }, - "engines": { - "node": ">=6.0" - }, - "optionalDependencies": { - "source-map": "~0.6.1" - } - }, "node_modules/esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", @@ -1811,24 +1637,6 @@ "node": ">=4" } }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/execa": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", @@ -1862,20 +1670,102 @@ } }, "node_modules/expect": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/expect/-/expect-27.5.1.tgz", - "integrity": "sha512-E1q5hSUG2AmYQwQJ041nvgpkODHQvB+RKlB4IYdru6uJsyFTRyZAP463M+1lINorwbqAmUggi6+WwkD8lCS/Dw==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/expect/-/expect-28.1.3.tgz", + "integrity": "sha512-eEh0xn8HlsuOBxFgIss+2mX85VAS4Qy3OSkjV7rlBWljtA4oWH37glVGyOZSZvErDT/yBywZdPGwCXuTvSG85g==", "dev": true, "dependencies": { - "@jest/types": "^27.5.1", - "jest-get-type": "^27.5.1", - "jest-matcher-utils": "^27.5.1", - "jest-message-util": "^27.5.1" + "@jest/expect-utils": "^28.1.3", + "jest-get-type": "^28.0.2", + "jest-matcher-utils": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-util": "^28.1.3" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/expect/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/expect/node_modules/diff-sequences": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.1.1.tgz", + "integrity": "sha512-FU0iFaH/E23a+a718l8Qa/19bF9p06kgE0KipMOMadwa3SjnaElKzPaUC0vnibs6/B/9ni97s61mcejk8W1fQw==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/expect/node_modules/jest-diff": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-28.1.3.tgz", + "integrity": "sha512-8RqP1B/OXzjjTWkqMX67iqgwBVJRgCyKD3L9nq+6ZqJMdvjE8RgHktqZ6jNrkdMT+dJuYNI3rhQpxaz7drJHfw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^28.1.1", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, + "node_modules/expect/node_modules/jest-get-type": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", + "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/expect/node_modules/jest-matcher-utils": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-28.1.3.tgz", + "integrity": "sha512-kQeJ7qHemKfbzKoGjHHrRKH6atgxMk8Enkk2iPQ3XwO6oE/KYD8lMYOziCkeSB9G4adPM4nR1DE8Tf5JeWH6Bw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^28.1.3", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/expect/node_modules/pretty-format": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.3.tgz", + "integrity": "sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==", + "dev": true, + "dependencies": { + "@jest/schemas": "^28.1.3", + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/expect/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true + }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -1901,9 +1791,9 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "dependencies": { "to-regex-range": "^5.0.1" @@ -1925,20 +1815,6 @@ "node": ">=8" } }, - "node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dev": true, - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/formdata-node": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz", @@ -1972,10 +1848,13 @@ } }, "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/gensync": { "version": "1.0.0-beta.2", @@ -2020,6 +1899,7 @@ "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, "dependencies": { "fs.realpath": "^1.0.0", @@ -2051,18 +1931,6 @@ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -2072,16 +1940,16 @@ "node": ">=8" } }, - "node_modules/html-encoding-sniffer": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz", - "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==", + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dev": true, "dependencies": { - "whatwg-encoding": "^1.0.5" + "function-bind": "^1.1.2" }, "engines": { - "node": ">=10" + "node": ">= 0.4" } }, "node_modules/html-escaper": { @@ -2090,33 +1958,6 @@ "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "dev": true }, - "node_modules/http-proxy-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", - "dev": true, - "dependencies": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "dev": true, - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/human-signals": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", @@ -2126,22 +1967,10 @@ "node": ">=10.17.0" } }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.2.0.tgz", + "integrity": "sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==", "dev": true, "dependencies": { "pkg-dir": "^4.2.0", @@ -2170,6 +1999,7 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "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.", "dev": true, "dependencies": { "once": "^1.3.0", @@ -2189,12 +2019,15 @@ "dev": true }, "node_modules/is-core-module": { - "version": "2.13.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz", - "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==", + "version": "2.15.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", + "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", "dev": true, "dependencies": { - "has": "^1.0.3" + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -2227,12 +2060,6 @@ "node": ">=0.12.0" } }, - "node_modules/is-potential-custom-element-name": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", - "dev": true - }, "node_modules/is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", @@ -2245,12 +2072,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", - "dev": true - }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -2258,9 +2079,9 @@ "dev": true }, "node_modules/istanbul-lib-coverage": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", - "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", "dev": true, "engines": { "node": ">=8" @@ -2311,9 +2132,9 @@ } }, "node_modules/istanbul-reports": { - "version": "3.1.6", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.6.tgz", - "integrity": "sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg==", + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", + "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", "dev": true, "dependencies": { "html-escaper": "^2.0.0", @@ -2324,20 +2145,21 @@ } }, "node_modules/jest": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest/-/jest-27.5.1.tgz", - "integrity": "sha512-Yn0mADZB89zTtjkPJEXwrac3LHudkQMR+Paqa8uxJHCBr9agxztUifWCyiYrjhMPBoUVBjyny0I7XH6ozDr7QQ==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest/-/jest-28.1.3.tgz", + "integrity": "sha512-N4GT5on8UkZgH0O5LUavMRV1EDEhNTL0KEfRmDIeZHSV7p2XgLoY9t9VDUgL6o+yfdgYHVxuz81G8oB9VG5uyA==", "dev": true, "dependencies": { - "@jest/core": "^27.5.1", + "@jest/core": "^28.1.3", + "@jest/types": "^28.1.3", "import-local": "^3.0.2", - "jest-cli": "^27.5.1" + "jest-cli": "^28.1.3" }, "bin": { "jest": "bin/jest.js" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" }, "peerDependencies": { "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" @@ -2349,73 +2171,153 @@ } }, "node_modules/jest-changed-files": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.5.1.tgz", - "integrity": "sha512-buBLMiByfWGCoMsLLzGUUSpAmIAGnbR2KJoMN10ziLhOLvP4e0SlypHnAel8iqQXTrcbmfEY9sSqae5sgUsTvw==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-28.1.3.tgz", + "integrity": "sha512-esaOfUWJXk2nfZt9SPyC8gA1kNfdKLkQWyzsMlqq8msYSlNKfmZxfRgZn4Cd4MGVUF+7v6dBs0d5TOAKa7iIiA==", "dev": true, "dependencies": { - "@jest/types": "^27.5.1", "execa": "^5.0.0", - "throat": "^6.0.1" + "p-limit": "^3.1.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, "node_modules/jest-circus": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-27.5.1.tgz", - "integrity": "sha512-D95R7x5UtlMA5iBYsOHFFbMD/GVA4R/Kdq15f7xYWUfWHBto9NYRsOvnSauTgdF+ogCpJ4tyKOXhUifxS65gdw==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-28.1.3.tgz", + "integrity": "sha512-cZ+eS5zc79MBwt+IhQhiEp0OeBddpc1n8MBo1nMB8A7oPMKEO+Sre+wHaLJexQUj9Ya/8NOBY0RESUgYjB6fow==", "dev": true, "dependencies": { - "@jest/environment": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/types": "^27.5.1", + "@jest/environment": "^28.1.3", + "@jest/expect": "^28.1.3", + "@jest/test-result": "^28.1.3", + "@jest/types": "^28.1.3", "@types/node": "*", "chalk": "^4.0.0", "co": "^4.6.0", "dedent": "^0.7.0", - "expect": "^27.5.1", "is-generator-fn": "^2.0.0", - "jest-each": "^27.5.1", - "jest-matcher-utils": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-runtime": "^27.5.1", - "jest-snapshot": "^27.5.1", - "jest-util": "^27.5.1", - "pretty-format": "^27.5.1", + "jest-each": "^28.1.3", + "jest-matcher-utils": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-runtime": "^28.1.3", + "jest-snapshot": "^28.1.3", + "jest-util": "^28.1.3", + "p-limit": "^3.1.0", + "pretty-format": "^28.1.3", "slash": "^3.0.0", - "stack-utils": "^2.0.3", - "throat": "^6.0.1" + "stack-utils": "^2.0.3" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, + "node_modules/jest-circus/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-circus/node_modules/diff-sequences": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.1.1.tgz", + "integrity": "sha512-FU0iFaH/E23a+a718l8Qa/19bF9p06kgE0KipMOMadwa3SjnaElKzPaUC0vnibs6/B/9ni97s61mcejk8W1fQw==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-circus/node_modules/jest-diff": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-28.1.3.tgz", + "integrity": "sha512-8RqP1B/OXzjjTWkqMX67iqgwBVJRgCyKD3L9nq+6ZqJMdvjE8RgHktqZ6jNrkdMT+dJuYNI3rhQpxaz7drJHfw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^28.1.1", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-circus/node_modules/jest-get-type": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", + "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-circus/node_modules/jest-matcher-utils": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-28.1.3.tgz", + "integrity": "sha512-kQeJ7qHemKfbzKoGjHHrRKH6atgxMk8Enkk2iPQ3XwO6oE/KYD8lMYOziCkeSB9G4adPM4nR1DE8Tf5JeWH6Bw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^28.1.3", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.3" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-circus/node_modules/pretty-format": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.3.tgz", + "integrity": "sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==", + "dev": true, + "dependencies": { + "@jest/schemas": "^28.1.3", + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-circus/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true + }, "node_modules/jest-cli": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-27.5.1.tgz", - "integrity": "sha512-Hc6HOOwYq4/74/c62dEE3r5elx8wjYqxY0r0G/nFrLDPMFRu6RA/u8qINOIkvhxG7mMQ5EJsOGfRpI8L6eFUVw==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-28.1.3.tgz", + "integrity": "sha512-roY3kvrv57Azn1yPgdTebPAXvdR2xfezaKKYzVxZ6It/5NCxzJym6tUI5P1zkdWhfUYkxEI9uZWcQdaFLo8mJQ==", "dev": true, "dependencies": { - "@jest/core": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/types": "^27.5.1", + "@jest/core": "^28.1.3", + "@jest/test-result": "^28.1.3", + "@jest/types": "^28.1.3", "chalk": "^4.0.0", "exit": "^0.1.2", "graceful-fs": "^4.2.9", "import-local": "^3.0.2", - "jest-config": "^27.5.1", - "jest-util": "^27.5.1", - "jest-validate": "^27.5.1", + "jest-config": "^28.1.3", + "jest-util": "^28.1.3", + "jest-validate": "^28.1.3", "prompts": "^2.0.1", - "yargs": "^16.2.0" + "yargs": "^17.3.1" }, "bin": { "jest": "bin/jest.js" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" }, "peerDependencies": { "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" @@ -2427,48 +2329,92 @@ } }, "node_modules/jest-config": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.5.1.tgz", - "integrity": "sha512-5sAsjm6tGdsVbW9ahcChPAFCk4IlkQUknH5AvKjuLTSlcO/wCZKyFdn7Rg0EkC+OGgWODEy2hDpWB1PgzH0JNA==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-28.1.3.tgz", + "integrity": "sha512-MG3INjByJ0J4AsNBm7T3hsuxKQqFIiRo/AUqb1q9LRKI5UU6Aar9JHbr9Ivn1TVwfUD9KirRoM/T6u8XlcQPHQ==", "dev": true, "dependencies": { - "@babel/core": "^7.8.0", - "@jest/test-sequencer": "^27.5.1", - "@jest/types": "^27.5.1", - "babel-jest": "^27.5.1", + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^28.1.3", + "@jest/types": "^28.1.3", + "babel-jest": "^28.1.3", "chalk": "^4.0.0", "ci-info": "^3.2.0", "deepmerge": "^4.2.2", - "glob": "^7.1.1", + "glob": "^7.1.3", "graceful-fs": "^4.2.9", - "jest-circus": "^27.5.1", - "jest-environment-jsdom": "^27.5.1", - "jest-environment-node": "^27.5.1", - "jest-get-type": "^27.5.1", - "jest-jasmine2": "^27.5.1", - "jest-regex-util": "^27.5.1", - "jest-resolve": "^27.5.1", - "jest-runner": "^27.5.1", - "jest-util": "^27.5.1", - "jest-validate": "^27.5.1", + "jest-circus": "^28.1.3", + "jest-environment-node": "^28.1.3", + "jest-get-type": "^28.0.2", + "jest-regex-util": "^28.0.2", + "jest-resolve": "^28.1.3", + "jest-runner": "^28.1.3", + "jest-util": "^28.1.3", + "jest-validate": "^28.1.3", "micromatch": "^4.0.4", "parse-json": "^5.2.0", - "pretty-format": "^27.5.1", + "pretty-format": "^28.1.3", "slash": "^3.0.0", "strip-json-comments": "^3.1.1" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" }, "peerDependencies": { + "@types/node": "*", "ts-node": ">=9.0.0" }, "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, "ts-node": { "optional": true } } }, + "node_modules/jest-config/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-config/node_modules/jest-get-type": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", + "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-config/node_modules/pretty-format": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.3.tgz", + "integrity": "sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==", + "dev": true, + "dependencies": { + "@jest/schemas": "^28.1.3", + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-config/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true + }, "node_modules/jest-diff": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-27.5.1.tgz", @@ -2485,66 +2431,90 @@ } }, "node_modules/jest-docblock": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.5.1.tgz", - "integrity": "sha512-rl7hlABeTsRYxKiUfpHrQrG4e2obOiTQWfMEH3PxPjOtdsfLQO4ReWSZaQ7DETm4xu07rl4q/h4zcKXyU0/OzQ==", + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-28.1.1.tgz", + "integrity": "sha512-3wayBVNiOYx0cwAbl9rwm5kKFP8yHH3d/fkEaL02NPTkDojPtheGB7HZSFY4wzX+DxyrvhXz0KSCVksmCknCuA==", "dev": true, "dependencies": { "detect-newline": "^3.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, "node_modules/jest-each": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-27.5.1.tgz", - "integrity": "sha512-1Ff6p+FbhT/bXQnEouYy00bkNSY7OUpfIcmdl8vZ31A1UUaurOLPA8a8BbJOF2RDUElwJhmeaV7LnagI+5UwNQ==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-28.1.3.tgz", + "integrity": "sha512-arT1z4sg2yABU5uogObVPvSlSMQlDA48owx07BDPAiasW0yYpYHYOo4HHLz9q0BVzDVU4hILFjzJw0So9aCL/g==", "dev": true, "dependencies": { - "@jest/types": "^27.5.1", + "@jest/types": "^28.1.3", "chalk": "^4.0.0", - "jest-get-type": "^27.5.1", - "jest-util": "^27.5.1", - "pretty-format": "^27.5.1" + "jest-get-type": "^28.0.2", + "jest-util": "^28.1.3", + "pretty-format": "^28.1.3" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, - "node_modules/jest-environment-jsdom": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.5.1.tgz", - "integrity": "sha512-TFBvkTC1Hnnnrka/fUb56atfDtJ9VMZ94JkjTbggl1PEpwrYtUBKMezB3inLmWqQsXYLcMwNoDQwoBTAvFfsfw==", + "node_modules/jest-each/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-each/node_modules/jest-get-type": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", + "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-each/node_modules/pretty-format": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.3.tgz", + "integrity": "sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==", "dev": true, "dependencies": { - "@jest/environment": "^27.5.1", - "@jest/fake-timers": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "jest-mock": "^27.5.1", - "jest-util": "^27.5.1", - "jsdom": "^16.6.0" + "@jest/schemas": "^28.1.3", + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, + "node_modules/jest-each/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true + }, "node_modules/jest-environment-node": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.5.1.tgz", - "integrity": "sha512-Jt4ZUnxdOsTGwSRAfKEnE6BcwsSPNOijjwifq5sDFSA2kesnXTvNqKHYgM0hDq3549Uf/KzdXNYn4wMZJPlFLw==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-28.1.3.tgz", + "integrity": "sha512-ugP6XOhEpjAEhGYvp5Xj989ns5cB1K6ZdjBYuS30umT4CQEETaxSiPcZ/E1kFktX4GkrcM4qu07IIlDYX1gp+A==", "dev": true, "dependencies": { - "@jest/environment": "^27.5.1", - "@jest/fake-timers": "^27.5.1", - "@jest/types": "^27.5.1", + "@jest/environment": "^28.1.3", + "@jest/fake-timers": "^28.1.3", + "@jest/types": "^28.1.3", "@types/node": "*", - "jest-mock": "^27.5.1", - "jest-util": "^27.5.1" + "jest-mock": "^28.1.3", + "jest-util": "^28.1.3" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, "node_modules/jest-get-type": { @@ -2557,72 +2527,85 @@ } }, "node_modules/jest-haste-map": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.5.1.tgz", - "integrity": "sha512-7GgkZ4Fw4NFbMSDSpZwXeBiIbx+t/46nJ2QitkOjvwPYyZmqttu2TDSimMHP1EkPOi4xUZAN1doE5Vd25H4Jng==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-28.1.3.tgz", + "integrity": "sha512-3S+RQWDXccXDKSWnkHa/dPwt+2qwA8CJzR61w3FoYCvoo3Pn8tvGcysmMF0Bj0EX5RYvAI2EIvC57OmotfdtKA==", "dev": true, "dependencies": { - "@jest/types": "^27.5.1", - "@types/graceful-fs": "^4.1.2", + "@jest/types": "^28.1.3", + "@types/graceful-fs": "^4.1.3", "@types/node": "*", "anymatch": "^3.0.3", "fb-watchman": "^2.0.0", "graceful-fs": "^4.2.9", - "jest-regex-util": "^27.5.1", - "jest-serializer": "^27.5.1", - "jest-util": "^27.5.1", - "jest-worker": "^27.5.1", + "jest-regex-util": "^28.0.2", + "jest-util": "^28.1.3", + "jest-worker": "^28.1.3", "micromatch": "^4.0.4", - "walker": "^1.0.7" + "walker": "^1.0.8" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" }, "optionalDependencies": { "fsevents": "^2.3.2" } }, - "node_modules/jest-jasmine2": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.5.1.tgz", - "integrity": "sha512-jtq7VVyG8SqAorDpApwiJJImd0V2wv1xzdheGHRGyuT7gZm6gG47QEskOlzsN1PG/6WNaCo5pmwMHDf3AkG2pQ==", + "node_modules/jest-leak-detector": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-28.1.3.tgz", + "integrity": "sha512-WFVJhnQsiKtDEo5lG2mM0v40QWnBM+zMdHHyJs8AWZ7J0QZJS59MsyKeJHWhpBZBH32S48FOVvGyOFT1h0DlqA==", "dev": true, "dependencies": { - "@jest/environment": "^27.5.1", - "@jest/source-map": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/node": "*", - "chalk": "^4.0.0", - "co": "^4.6.0", - "expect": "^27.5.1", - "is-generator-fn": "^2.0.0", - "jest-each": "^27.5.1", - "jest-matcher-utils": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-runtime": "^27.5.1", - "jest-snapshot": "^27.5.1", - "jest-util": "^27.5.1", - "pretty-format": "^27.5.1", - "throat": "^6.0.1" + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.3" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, - "node_modules/jest-leak-detector": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.5.1.tgz", - "integrity": "sha512-POXfWAMvfU6WMUXftV4HolnJfnPOGEu10fscNCA76KBpRRhcMN2c8d3iT2pxQS3HLbA+5X4sOUPzYO2NUyIlHQ==", + "node_modules/jest-leak-detector/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-leak-detector/node_modules/jest-get-type": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", + "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-leak-detector/node_modules/pretty-format": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.3.tgz", + "integrity": "sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==", "dev": true, "dependencies": { - "jest-get-type": "^27.5.1", - "pretty-format": "^27.5.1" + "@jest/schemas": "^28.1.3", + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, + "node_modules/jest-leak-detector/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true + }, "node_modules/jest-matcher-utils": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz", @@ -2639,36 +2622,69 @@ } }, "node_modules/jest-message-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.5.1.tgz", - "integrity": "sha512-rMyFe1+jnyAAf+NHwTclDz0eAaLkVDdKVHHBFWsBWHnnh5YeJMNWWsv7AbFYXfK3oTqvL7VTWkhNLu1jX24D+g==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-28.1.3.tgz", + "integrity": "sha512-PFdn9Iewbt575zKPf1286Ht9EPoJmYT7P0kY+RibeYZ2XtOr53pDLEFoTWXbd1h4JiGiWpTBC84fc8xMXQMb7g==", "dev": true, "dependencies": { "@babel/code-frame": "^7.12.13", - "@jest/types": "^27.5.1", + "@jest/types": "^28.1.3", "@types/stack-utils": "^2.0.0", "chalk": "^4.0.0", "graceful-fs": "^4.2.9", "micromatch": "^4.0.4", - "pretty-format": "^27.5.1", + "pretty-format": "^28.1.3", "slash": "^3.0.0", "stack-utils": "^2.0.3" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, + "node_modules/jest-message-util/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-message-util/node_modules/pretty-format": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.3.tgz", + "integrity": "sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==", + "dev": true, + "dependencies": { + "@jest/schemas": "^28.1.3", + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-message-util/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true + }, "node_modules/jest-mock": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-27.5.1.tgz", - "integrity": "sha512-K4jKbY1d4ENhbrG2zuPWaQBvDly+iZ2yAW+T1fATN78hc0sInwn7wZB8XtlNnvHug5RMwV897Xm4LqmPM4e2Og==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-28.1.3.tgz", + "integrity": "sha512-o3J2jr6dMMWYVH4Lh/NKmDXdosrsJgi4AviS8oXLujcjpCMBb1FMsblDnOXKZKfSiHLxYub1eS0IHuRXsio9eA==", "dev": true, "dependencies": { - "@jest/types": "^27.5.1", + "@jest/types": "^28.1.3", "@types/node": "*" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, "node_modules/jest-pnp-resolver": { @@ -2689,180 +2705,232 @@ } }, "node_modules/jest-regex-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.5.1.tgz", - "integrity": "sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg==", + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-28.0.2.tgz", + "integrity": "sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw==", "dev": true, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, "node_modules/jest-resolve": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.5.1.tgz", - "integrity": "sha512-FFDy8/9E6CV83IMbDpcjOhumAQPDyETnU2KZ1O98DwTnz8AOBsW/Xv3GySr1mOZdItLR+zDZ7I/UdTFbgSOVCw==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-28.1.3.tgz", + "integrity": "sha512-Z1W3tTjE6QaNI90qo/BJpfnvpxtaFTFw5CDgwpyE/Kz8U/06N1Hjf4ia9quUhCh39qIGWF1ZuxFiBiJQwSEYKQ==", "dev": true, "dependencies": { - "@jest/types": "^27.5.1", "chalk": "^4.0.0", "graceful-fs": "^4.2.9", - "jest-haste-map": "^27.5.1", + "jest-haste-map": "^28.1.3", "jest-pnp-resolver": "^1.2.2", - "jest-util": "^27.5.1", - "jest-validate": "^27.5.1", + "jest-util": "^28.1.3", + "jest-validate": "^28.1.3", "resolve": "^1.20.0", "resolve.exports": "^1.1.0", "slash": "^3.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, "node_modules/jest-resolve-dependencies": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.5.1.tgz", - "integrity": "sha512-QQOOdY4PE39iawDn5rzbIePNigfe5B9Z91GDD1ae/xNDlu9kaat8QQ5EKnNmVWPV54hUdxCVwwj6YMgR2O7IOg==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-28.1.3.tgz", + "integrity": "sha512-qa0QO2Q0XzQoNPouMbCc7Bvtsem8eQgVPNkwn9LnS+R2n8DaVDPL/U1gngC0LTl1RYXJU0uJa2BMC2DbTfFrHA==", "dev": true, "dependencies": { - "@jest/types": "^27.5.1", - "jest-regex-util": "^27.5.1", - "jest-snapshot": "^27.5.1" + "jest-regex-util": "^28.0.2", + "jest-snapshot": "^28.1.3" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, "node_modules/jest-runner": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-27.5.1.tgz", - "integrity": "sha512-g4NPsM4mFCOwFKXO4p/H/kWGdJp9V8kURY2lX8Me2drgXqG7rrZAx5kv+5H7wtt/cdFIjhqYx1HrlqWHaOvDaQ==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-28.1.3.tgz", + "integrity": "sha512-GkMw4D/0USd62OVO0oEgjn23TM+YJa2U2Wu5zz9xsQB1MxWKDOlrnykPxnMsN0tnJllfLPinHTka61u0QhaxBA==", "dev": true, "dependencies": { - "@jest/console": "^27.5.1", - "@jest/environment": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", + "@jest/console": "^28.1.3", + "@jest/environment": "^28.1.3", + "@jest/test-result": "^28.1.3", + "@jest/transform": "^28.1.3", + "@jest/types": "^28.1.3", "@types/node": "*", "chalk": "^4.0.0", - "emittery": "^0.8.1", + "emittery": "^0.10.2", "graceful-fs": "^4.2.9", - "jest-docblock": "^27.5.1", - "jest-environment-jsdom": "^27.5.1", - "jest-environment-node": "^27.5.1", - "jest-haste-map": "^27.5.1", - "jest-leak-detector": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-resolve": "^27.5.1", - "jest-runtime": "^27.5.1", - "jest-util": "^27.5.1", - "jest-worker": "^27.5.1", - "source-map-support": "^0.5.6", - "throat": "^6.0.1" + "jest-docblock": "^28.1.1", + "jest-environment-node": "^28.1.3", + "jest-haste-map": "^28.1.3", + "jest-leak-detector": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-resolve": "^28.1.3", + "jest-runtime": "^28.1.3", + "jest-util": "^28.1.3", + "jest-watcher": "^28.1.3", + "jest-worker": "^28.1.3", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, "node_modules/jest-runtime": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.5.1.tgz", - "integrity": "sha512-o7gxw3Gf+H2IGt8fv0RiyE1+r83FJBRruoA+FXrlHw6xEyBsU8ugA6IPfTdVyA0w8HClpbK+DGJxH59UrNMx8A==", - "dev": true, - "dependencies": { - "@jest/environment": "^27.5.1", - "@jest/fake-timers": "^27.5.1", - "@jest/globals": "^27.5.1", - "@jest/source-map": "^27.5.1", - "@jest/test-result": "^27.5.1", - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-28.1.3.tgz", + "integrity": "sha512-NU+881ScBQQLc1JHG5eJGU7Ui3kLKrmwCPPtYsJtBykixrM2OhVQlpMmFWJjMyDfdkGgBMNjXCGB/ebzsgNGQw==", + "dev": true, + "dependencies": { + "@jest/environment": "^28.1.3", + "@jest/fake-timers": "^28.1.3", + "@jest/globals": "^28.1.3", + "@jest/source-map": "^28.1.2", + "@jest/test-result": "^28.1.3", + "@jest/transform": "^28.1.3", + "@jest/types": "^28.1.3", "chalk": "^4.0.0", "cjs-module-lexer": "^1.0.0", "collect-v8-coverage": "^1.0.0", "execa": "^5.0.0", "glob": "^7.1.3", "graceful-fs": "^4.2.9", - "jest-haste-map": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-mock": "^27.5.1", - "jest-regex-util": "^27.5.1", - "jest-resolve": "^27.5.1", - "jest-snapshot": "^27.5.1", - "jest-util": "^27.5.1", + "jest-haste-map": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-mock": "^28.1.3", + "jest-regex-util": "^28.0.2", + "jest-resolve": "^28.1.3", + "jest-snapshot": "^28.1.3", + "jest-util": "^28.1.3", "slash": "^3.0.0", "strip-bom": "^4.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" - } - }, - "node_modules/jest-serializer": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.5.1.tgz", - "integrity": "sha512-jZCyo6iIxO1aqUxpuBlwTDMkzOAJS4a3eYz3YzgxxVQFwLeSA7Jfq5cbqCY+JLvTDrWirgusI/0KwxKMgrdf7w==", - "dev": true, - "dependencies": { - "@types/node": "*", - "graceful-fs": "^4.2.9" - }, - "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, "node_modules/jest-snapshot": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.5.1.tgz", - "integrity": "sha512-yYykXI5a0I31xX67mgeLw1DZ0bJB+gpq5IpSuCAoyDi0+BhgU/RIrL+RTzDmkNTchvDFWKP8lp+w/42Z3us5sA==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-28.1.3.tgz", + "integrity": "sha512-4lzMgtiNlc3DU/8lZfmqxN3AYD6GGLbl+72rdBpXvcV+whX7mDrREzkPdp2RnmfIiWBg1YbuFSkXduF2JcafJg==", "dev": true, "dependencies": { - "@babel/core": "^7.7.2", + "@babel/core": "^7.11.6", "@babel/generator": "^7.7.2", "@babel/plugin-syntax-typescript": "^7.7.2", "@babel/traverse": "^7.7.2", - "@babel/types": "^7.0.0", - "@jest/transform": "^27.5.1", - "@jest/types": "^27.5.1", - "@types/babel__traverse": "^7.0.4", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^28.1.3", + "@jest/transform": "^28.1.3", + "@jest/types": "^28.1.3", + "@types/babel__traverse": "^7.0.6", "@types/prettier": "^2.1.5", "babel-preset-current-node-syntax": "^1.0.0", "chalk": "^4.0.0", - "expect": "^27.5.1", + "expect": "^28.1.3", "graceful-fs": "^4.2.9", - "jest-diff": "^27.5.1", - "jest-get-type": "^27.5.1", - "jest-haste-map": "^27.5.1", - "jest-matcher-utils": "^27.5.1", - "jest-message-util": "^27.5.1", - "jest-util": "^27.5.1", + "jest-diff": "^28.1.3", + "jest-get-type": "^28.0.2", + "jest-haste-map": "^28.1.3", + "jest-matcher-utils": "^28.1.3", + "jest-message-util": "^28.1.3", + "jest-util": "^28.1.3", "natural-compare": "^1.4.0", - "pretty-format": "^27.5.1", - "semver": "^7.3.2" + "pretty-format": "^28.1.3", + "semver": "^7.3.5" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, - "node_modules/jest-snapshot/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "node_modules/jest-snapshot/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-snapshot/node_modules/diff-sequences": { + "version": "28.1.1", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-28.1.1.tgz", + "integrity": "sha512-FU0iFaH/E23a+a718l8Qa/19bF9p06kgE0KipMOMadwa3SjnaElKzPaUC0vnibs6/B/9ni97s61mcejk8W1fQw==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/jest-diff": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-28.1.3.tgz", + "integrity": "sha512-8RqP1B/OXzjjTWkqMX67iqgwBVJRgCyKD3L9nq+6ZqJMdvjE8RgHktqZ6jNrkdMT+dJuYNI3rhQpxaz7drJHfw==", "dev": true, "dependencies": { - "yallist": "^4.0.0" + "chalk": "^4.0.0", + "diff-sequences": "^28.1.1", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.3" }, "engines": { - "node": ">=10" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, - "node_modules/jest-snapshot/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "node_modules/jest-snapshot/node_modules/jest-get-type": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", + "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/jest-matcher-utils": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-28.1.3.tgz", + "integrity": "sha512-kQeJ7qHemKfbzKoGjHHrRKH6atgxMk8Enkk2iPQ3XwO6oE/KYD8lMYOziCkeSB9G4adPM4nR1DE8Tf5JeWH6Bw==", "dev": true, "dependencies": { - "lru-cache": "^6.0.0" + "chalk": "^4.0.0", + "jest-diff": "^28.1.3", + "jest-get-type": "^28.0.2", + "pretty-format": "^28.1.3" }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/pretty-format": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.3.tgz", + "integrity": "sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==", + "dev": true, + "dependencies": { + "@jest/schemas": "^28.1.3", + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true + }, + "node_modules/jest-snapshot/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, "bin": { "semver": "bin/semver.js" }, @@ -2870,19 +2938,13 @@ "node": ">=10" } }, - "node_modules/jest-snapshot/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/jest-util": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-27.5.1.tgz", - "integrity": "sha512-Kv2o/8jNvX1MQ0KGtw480E/w4fBCDOnH6+6DmeKi6LZUIlKA5kwY0YNdlzaWTiVgxqAqik11QyxDOKk543aKXw==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-28.1.3.tgz", + "integrity": "sha512-XdqfpHwpcSRko/C35uLYFM2emRAltIIKZiJ9eAmhjsj0CqZMa0p1ib0R5fWIqGhn1a103DebTbpqIaP1qCQ6tQ==", "dev": true, "dependencies": { - "@jest/types": "^27.5.1", + "@jest/types": "^28.1.3", "@types/node": "*", "chalk": "^4.0.0", "ci-info": "^3.2.0", @@ -2890,24 +2952,36 @@ "picomatch": "^2.2.3" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, "node_modules/jest-validate": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-27.5.1.tgz", - "integrity": "sha512-thkNli0LYTmOI1tDB3FI1S1RTp/Bqyd9pTarJwL87OIBFuqEb5Apv5EaApEudYg4g86e3CT6kM0RowkhtEnCBQ==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-28.1.3.tgz", + "integrity": "sha512-SZbOGBWEsaTxBGCOpsRWlXlvNkvTkY0XxRfh7zYmvd8uL5Qzyg0CHAXiXKROflh801quA6+/DsT4ODDthOC/OA==", "dev": true, "dependencies": { - "@jest/types": "^27.5.1", + "@jest/types": "^28.1.3", "camelcase": "^6.2.0", "chalk": "^4.0.0", - "jest-get-type": "^27.5.1", + "jest-get-type": "^28.0.2", "leven": "^3.1.0", - "pretty-format": "^27.5.1" + "pretty-format": "^28.1.3" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-validate/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, "node_modules/jest-validate/node_modules/camelcase": { @@ -2922,28 +2996,59 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/jest-validate/node_modules/jest-get-type": { + "version": "28.0.2", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-28.0.2.tgz", + "integrity": "sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA==", + "dev": true, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-validate/node_modules/pretty-format": { + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-28.1.3.tgz", + "integrity": "sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q==", + "dev": true, + "dependencies": { + "@jest/schemas": "^28.1.3", + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" + } + }, + "node_modules/jest-validate/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "dev": true + }, "node_modules/jest-watcher": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.5.1.tgz", - "integrity": "sha512-z676SuD6Z8o8qbmEGhoEUFOM1+jfEiL3DXHK/xgEiG2EyNYfFG60jluWcupY6dATjfEsKQuibReS1djInQnoVw==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-28.1.3.tgz", + "integrity": "sha512-t4qcqj9hze+jviFPUN3YAtAEeFnr/azITXQEMARf5cMwKY2SMBRnCQTXLixTl20OR6mLh9KLMrgVJgJISym+1g==", "dev": true, "dependencies": { - "@jest/test-result": "^27.5.1", - "@jest/types": "^27.5.1", + "@jest/test-result": "^28.1.3", + "@jest/types": "^28.1.3", "@types/node": "*", "ansi-escapes": "^4.2.1", "chalk": "^4.0.0", - "jest-util": "^27.5.1", + "emittery": "^0.10.2", + "jest-util": "^28.1.3", "string-length": "^4.0.1" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, "node_modules/jest-worker": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", - "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "version": "28.1.3", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-28.1.3.tgz", + "integrity": "sha512-CqRA220YV/6jCo8VWvAt1KKx6eek1VIHMPeLEbpcfSfkEeWyBNppynM/o6q+Wmw+sOhos2ml34wZbSX3G13//g==", "dev": true, "dependencies": { "@types/node": "*", @@ -2951,7 +3056,7 @@ "supports-color": "^8.0.0" }, "engines": { - "node": ">= 10.13.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, "node_modules/jest-worker/node_modules/supports-color": { @@ -2988,66 +3093,6 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/jsdom": { - "version": "16.7.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz", - "integrity": "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw==", - "dev": true, - "dependencies": { - "abab": "^2.0.5", - "acorn": "^8.2.4", - "acorn-globals": "^6.0.0", - "cssom": "^0.4.4", - "cssstyle": "^2.3.0", - "data-urls": "^2.0.0", - "decimal.js": "^10.2.1", - "domexception": "^2.0.1", - "escodegen": "^2.0.0", - "form-data": "^3.0.0", - "html-encoding-sniffer": "^2.0.1", - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "is-potential-custom-element-name": "^1.0.1", - "nwsapi": "^2.2.0", - "parse5": "6.0.1", - "saxes": "^5.0.1", - "symbol-tree": "^3.2.4", - "tough-cookie": "^4.0.0", - "w3c-hr-time": "^1.0.2", - "w3c-xmlserializer": "^2.0.0", - "webidl-conversions": "^6.1.0", - "whatwg-encoding": "^1.0.5", - "whatwg-mimetype": "^2.3.0", - "whatwg-url": "^8.5.0", - "ws": "^7.4.6", - "xml-name-validator": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "peerDependencies": { - "canvas": "^2.5.0" - }, - "peerDependenciesMeta": { - "canvas": { - "optional": true - } - } - }, - "node_modules/jsdom/node_modules/form-data": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz", - "integrity": "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==", - "dev": true, - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -3113,12 +3158,6 @@ "node": ">=8" } }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, "node_modules/lodash.memoize": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", @@ -3149,26 +3188,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/make-dir/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/make-dir/node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, "bin": { "semver": "bin/semver.js" }, @@ -3176,12 +3200,6 @@ "node": ">=10" } }, - "node_modules/make-dir/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, "node_modules/make-error": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", @@ -3204,39 +3222,18 @@ "dev": true }, "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, "dependencies": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { "node": ">=8.6" } }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/mimic-fn": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", @@ -3267,9 +3264,9 @@ } }, "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, "node_modules/natural-compare": { @@ -3296,44 +3293,6 @@ "node": ">=10.5.0" } }, - "node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/node-fetch/node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" - }, - "node_modules/node-fetch/node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" - }, - "node_modules/node-fetch/node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -3341,9 +3300,9 @@ "dev": true }, "node_modules/node-releases": { - "version": "2.0.13", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", - "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==", + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==", "dev": true }, "node_modules/normalize-path": { @@ -3367,12 +3326,6 @@ "node": ">=8" } }, - "node_modules/nwsapi": { - "version": "2.2.7", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.7.tgz", - "integrity": "sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ==", - "dev": true - }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -3398,15 +3351,15 @@ } }, "node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, "dependencies": { - "p-try": "^2.0.0" + "yocto-queue": "^0.1.0" }, "engines": { - "node": ">=6" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -3424,6 +3377,21 @@ "node": ">=8" } }, + "node_modules/p-locate/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", @@ -3451,12 +3419,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true - }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -3491,9 +3453,9 @@ "dev": true }, "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", + "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==", "dev": true }, "node_modules/picomatch": { @@ -3568,27 +3530,6 @@ "node": ">= 6" } }, - "node_modules/psl": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", - "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", - "dev": true - }, - "node_modules/punycode": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", - "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/querystringify": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", - "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", - "dev": true - }, "node_modules/react-is": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", @@ -3604,16 +3545,10 @@ "node": ">=0.10.0" } }, - "node_modules/requires-port": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", - "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", - "dev": true - }, "node_modules/resolve": { - "version": "1.22.4", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.4.tgz", - "integrity": "sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==", + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "dev": true, "dependencies": { "is-core-module": "^2.13.0", @@ -3661,6 +3596,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, "dependencies": { "glob": "^7.1.3" @@ -3672,24 +3608,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, - "node_modules/saxes": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz", - "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==", - "dev": true, - "dependencies": { - "xmlchars": "^2.2.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -3751,9 +3669,9 @@ } }, "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", "dev": true, "dependencies": { "buffer-from": "^1.0.0", @@ -3884,12 +3802,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/symbol-tree": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", - "dev": true - }, "node_modules/terminal-link": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz", @@ -3920,12 +3832,6 @@ "node": ">=8" } }, - "node_modules/throat": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/throat/-/throat-6.0.2.tgz", - "integrity": "sha512-WKexMoJj3vEuK0yFEapj8y64V0A6xcuPuK9Gt1d0R+dzCSJc0lHqQytAbSB4cDAK0dWh4T0E2ETkoLE2WZ41OQ==", - "dev": true - }, "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -3953,66 +3859,39 @@ "node": ">=8.0" } }, - "node_modules/tough-cookie": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", - "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", - "dev": true, - "dependencies": { - "psl": "^1.1.33", - "punycode": "^2.1.1", - "universalify": "^0.2.0", - "url-parse": "^1.5.3" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tr46": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz", - "integrity": "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==", - "dev": true, - "dependencies": { - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/ts-jest": { - "version": "27.1.5", - "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-27.1.5.tgz", - "integrity": "sha512-Xv6jBQPoBEvBq/5i2TeSG9tt/nqkbpcurrEG1b+2yfBrcJelOZF9Ml6dmyMh7bcW9JyFbRYpR5rxROSlBLTZHA==", + "version": "28.0.8", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-28.0.8.tgz", + "integrity": "sha512-5FaG0lXmRPzApix8oFG8RKjAz4ehtm8yMKOTy5HX3fY6W8kmvOrmcY0hKDElW52FJov+clhUbrKAqofnj4mXTg==", "dev": true, "dependencies": { "bs-logger": "0.x", "fast-json-stable-stringify": "2.x", - "jest-util": "^27.0.0", - "json5": "2.x", + "jest-util": "^28.0.0", + "json5": "^2.2.1", "lodash.memoize": "4.x", "make-error": "1.x", "semver": "7.x", - "yargs-parser": "20.x" + "yargs-parser": "^21.0.1" }, "bin": { "ts-jest": "cli.js" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" }, "peerDependencies": { "@babel/core": ">=7.0.0-beta.0 <8", - "@types/jest": "^27.0.0", - "babel-jest": ">=27.0.0 <28", - "jest": "^27.0.0", - "typescript": ">=3.8 <5.0" + "@jest/types": "^28.0.0", + "babel-jest": "^28.0.0", + "jest": "^28.0.0", + "typescript": ">=4.3" }, "peerDependenciesMeta": { "@babel/core": { "optional": true }, - "@types/jest": { + "@jest/types": { "optional": true }, "babel-jest": { @@ -4098,15 +3977,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/typedarray-to-buffer": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz", - "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", - "dev": true, - "dependencies": { - "is-typedarray": "^1.0.0" - } - }, "node_modules/typescript": { "version": "4.5.5", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz", @@ -4126,19 +3996,10 @@ "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", "dev": true }, - "node_modules/universalify": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", - "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", - "dev": true, - "engines": { - "node": ">= 4.0.0" - } - }, "node_modules/update-browserslist-db": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", - "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz", + "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==", "dev": true, "funding": [ { @@ -4155,8 +4016,8 @@ } ], "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" + "escalade": "^3.1.2", + "picocolors": "^1.0.1" }, "bin": { "update-browserslist-db": "cli.js" @@ -4165,60 +4026,25 @@ "browserslist": ">= 4.21.0" } }, - "node_modules/url-parse": { - "version": "1.5.10", - "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", - "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", - "dev": true, - "dependencies": { - "querystringify": "^2.1.1", - "requires-port": "^1.0.0" - } - }, "node_modules/v8-to-istanbul": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.1.tgz", - "integrity": "sha512-FGtKtv3xIpR6BYhvgH8MI/y78oT7d8Au3ww4QIxymrCtZEh5b8gCw2siywE+puhEmuWKDtmfrvF5UlB298ut3w==", + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz", + "integrity": "sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==", "dev": true, "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", "@types/istanbul-lib-coverage": "^2.0.1", - "convert-source-map": "^1.6.0", - "source-map": "^0.7.3" + "convert-source-map": "^2.0.0" }, "engines": { "node": ">=10.12.0" } }, - "node_modules/v8-to-istanbul/node_modules/source-map": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", - "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/w3c-hr-time": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", - "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==", - "deprecated": "Use your platform's native performance.now() and performance.timeOrigin.", - "dev": true, - "dependencies": { - "browser-process-hrtime": "^1.0.0" - } - }, - "node_modules/w3c-xmlserializer": { + "node_modules/v8-to-istanbul/node_modules/convert-source-map": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz", - "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==", - "dev": true, - "dependencies": { - "xml-name-validator": "^3.0.0" - }, - "engines": { - "node": ">=10" - } + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true }, "node_modules/walker": { "version": "1.0.8", @@ -4237,44 +4063,6 @@ "node": ">= 14" } }, - "node_modules/webidl-conversions": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz", - "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==", - "dev": true, - "engines": { - "node": ">=10.4" - } - }, - "node_modules/whatwg-encoding": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", - "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", - "dev": true, - "dependencies": { - "iconv-lite": "0.4.24" - } - }, - "node_modules/whatwg-mimetype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", - "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", - "dev": true - }, - "node_modules/whatwg-url": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz", - "integrity": "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==", - "dev": true, - "dependencies": { - "lodash": "^4.7.0", - "tr46": "^2.1.0", - "webidl-conversions": "^6.1.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -4314,50 +4102,18 @@ "dev": true }, "node_modules/write-file-atomic": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz", - "integrity": "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", "dev": true, "dependencies": { "imurmurhash": "^0.1.4", - "is-typedarray": "^1.0.0", - "signal-exit": "^3.0.2", - "typedarray-to-buffer": "^3.1.5" - } - }, - "node_modules/ws": { - "version": "7.5.9", - "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", - "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", - "dev": true, - "engines": { - "node": ">=8.3.0" + "signal-exit": "^3.0.7" }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, - "node_modules/xml-name-validator": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", - "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", - "dev": true - }, - "node_modules/xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", - "dev": true - }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", @@ -4374,30 +4130,42 @@ "dev": true }, "node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "dev": true, "dependencies": { - "cliui": "^7.0.2", + "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", - "string-width": "^4.2.0", + "string-width": "^4.2.3", "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" + "yargs-parser": "^21.1.1" }, "engines": { - "node": ">=10" + "node": ">=12" } }, "node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, "engines": { "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } } } diff --git a/ecosystem-tests/node-ts4.5-jest27/package.json b/ecosystem-tests/node-ts4.5-jest28/package.json similarity index 79% rename from ecosystem-tests/node-ts4.5-jest27/package.json rename to ecosystem-tests/node-ts4.5-jest28/package.json index ae76bcc9c..a083e09f3 100644 --- a/ecosystem-tests/node-ts4.5-jest27/package.json +++ b/ecosystem-tests/node-ts4.5-jest28/package.json @@ -9,17 +9,15 @@ }, "dependencies": { "formdata-node": "^4.4.1", - "node-fetch": "^2.6.1", "tsconfig-paths": "^4.0.0" }, "devDependencies": { "@types/node": "20.11.20", - "@types/node-fetch": "^2.6.1", "@types/jest": "27.5.2", "@types/ws": "^8.5.4", "fastest-levenshtein": "^1.0.16", - "jest": "27.5.1", - "ts-jest": "27.1.5", + "jest": "28.1.3", + "ts-jest": "^28.0.0", "typescript": "4.5.5" } } diff --git a/ecosystem-tests/node-ts4.5-jest27/sample1.mp3 b/ecosystem-tests/node-ts4.5-jest28/sample1.mp3 similarity index 100% rename from ecosystem-tests/node-ts4.5-jest27/sample1.mp3 rename to ecosystem-tests/node-ts4.5-jest28/sample1.mp3 diff --git a/ecosystem-tests/node-ts4.5-jest27/tests/test.ts b/ecosystem-tests/node-ts4.5-jest28/tests/test.ts similarity index 68% rename from ecosystem-tests/node-ts4.5-jest27/tests/test.ts rename to ecosystem-tests/node-ts4.5-jest28/tests/test.ts index 3f6e5d572..855a925c5 100644 --- a/ecosystem-tests/node-ts4.5-jest27/tests/test.ts +++ b/ecosystem-tests/node-ts4.5-jest28/tests/test.ts @@ -1,11 +1,10 @@ -import 'openai/shims/node'; import OpenAI, { toFile } from 'openai'; import { TranscriptionCreateParams } from 'openai/resources/audio/transcriptions'; -import fetch from 'node-fetch'; import { File as FormDataFile, Blob as FormDataBlob } from 'formdata-node'; import * as fs from 'fs'; import { distance } from 'fastest-levenshtein'; import { ChatCompletion } from 'openai/resources/chat/completions'; +import { File } from 'node:buffer'; const url = 'https://audio-samples.github.io/samples/mp3/blizzard_biased/sample-1.mp3'; const filename = 'sample-1.mp3'; @@ -65,13 +64,12 @@ it(`raw response`, async function () { }) .asResponse(); - // test that we can use node-fetch Response API + const decoder = new TextDecoder(); const chunks: string[] = []; - response.body.on('data', (chunk) => chunks.push(chunk)); - await new Promise((resolve, reject) => { - response.body.once('end', resolve); - response.body.once('error', reject); - }); + for await (const chunk of response.body!) { + chunks.push(decoder.decode(chunk)); + } + const json: ChatCompletion = JSON.parse(chunks.join('')); expect(json.choices[0]?.message.content || '').toBeSimilarTo('This is a test', 10); }); @@ -89,30 +87,24 @@ it(`streaming works`, async function () { expect(chunks.map((c) => c.choices[0]?.delta.content || '').join('')).toBeSimilarTo('This is a test', 10); }); -it('handles formdata-node File', async function () { +it('handles builtinFile', async function () { const file = await fetch(url) .then((x) => x.arrayBuffer()) - .then((x) => new FormDataFile([x], filename)); - - const params: TranscriptionCreateParams = { file, model }; + .then( + (x) => + new File( + [ + // @ts-ignore array buffer can't be passed to File at the type-level + x, + ], + filename, + ), + ); - const result = await client.audio.transcriptions.create(params); + const result = await client.audio.transcriptions.create({ file, model }); expect(result.text).toBeSimilarTo(correctAnswer, 12); }); -// @ts-ignore avoid DOM lib for testing purposes -if (typeof File !== 'undefined') { - it('handles builtinFile', async function () { - const file = await fetch(url) - .then((x) => x.arrayBuffer()) - // @ts-ignore avoid DOM lib for testing purposes - .then((x) => new File([x], filename)); - - const result = await client.audio.transcriptions.create({ file, model }); - expect(result.text).toBeSimilarTo(correctAnswer, 12); - }); -} - it('handles Response', async function () { const file = await fetch(url); @@ -133,26 +125,15 @@ const fineTune = `{"prompt": "", "completion": " { it('handles form-data Blob', async function () { const result = await client.files.create({ - file: await toFile( - new FormDataBlob([ - // @ts-ignore avoid DOM lib for testing purposes - new TextEncoder().encode(fineTune), - ]), - 'finetune.jsonl', - ), + file: await toFile(new FormDataBlob([new TextEncoder().encode(fineTune)]), 'finetune.jsonl'), purpose: 'fine-tune', }); expect(result.filename).toEqual('finetune.jsonl'); }); - // @ts-ignore avoid DOM lib for testing purposes if (typeof Blob !== 'undefined') { it('handles builtin Blob', async function () { const result = await client.files.create({ - file: await toFile( - // @ts-ignore avoid DOM lib for testing purposes - new Blob([new TextEncoder().encode(fineTune)]), - 'finetune.jsonl', - ), + file: await toFile(new Blob([new TextEncoder().encode(fineTune)]), 'finetune.jsonl'), purpose: 'fine-tune', }); expect(result.filename).toEqual('finetune.jsonl'); @@ -160,44 +141,36 @@ describe('toFile', () => { } it('handles Uint8Array', async function () { const result = await client.files.create({ - file: await toFile( - // @ts-ignore avoid DOM lib for testing purposes - new TextEncoder().encode(fineTune), - 'finetune.jsonl', - ), + file: await toFile(new TextEncoder().encode(fineTune), 'finetune.jsonl'), purpose: 'fine-tune', }); expect(result.filename).toEqual('finetune.jsonl'); }); it('handles ArrayBuffer', async function () { const result = await client.files.create({ - file: await toFile( - // @ts-ignore avoid DOM lib for testing purposes - new TextEncoder().encode(fineTune).buffer, - 'finetune.jsonl', - ), + file: await toFile(new TextEncoder().encode(fineTune).buffer, 'finetune.jsonl'), purpose: 'fine-tune', }); expect(result.filename).toEqual('finetune.jsonl'); }); it('handles DataView', async function () { const result = await client.files.create({ - file: await toFile( - // @ts-ignore avoid DOM lib for testing purposes - new DataView(new TextEncoder().encode(fineTune).buffer), - 'finetune.jsonl', - ), + file: await toFile(new DataView(new TextEncoder().encode(fineTune).buffer), 'finetune.jsonl'), purpose: 'fine-tune', }); expect(result.filename).toEqual('finetune.jsonl'); }); -}); -test('query strings', () => { - expect( - decodeURIComponent((client as any).stringifyQuery({ foo: { nested: { a: true, b: 'foo' } } })), - ).toEqual('foo[nested][a]=true&foo[nested][b]=foo'); - expect( - decodeURIComponent((client as any).stringifyQuery({ foo: { nested: { a: ['hello', 'world'] } } })), - ).toEqual('foo[nested][a][]=hello&foo[nested][a][]=world'); + it('handles formdata-node File', async function () { + const file = await fetch(url) + .then((x) => x.arrayBuffer()) + .then((x) => toFile(new FormDataFile([x], filename))); + + expect(file.name).toEqual(filename); + + const params: TranscriptionCreateParams = { file, model }; + + const result = await client.audio.transcriptions.create(params); + expect(result.text).toBeSimilarTo(correctAnswer, 12); + }); }); diff --git a/ecosystem-tests/node-ts4.5-jest27/tsconfig.json b/ecosystem-tests/node-ts4.5-jest28/tsconfig.json similarity index 100% rename from ecosystem-tests/node-ts4.5-jest27/tsconfig.json rename to ecosystem-tests/node-ts4.5-jest28/tsconfig.json diff --git a/ecosystem-tests/nodenext-tsup/index.ts b/ecosystem-tests/nodenext-tsup/index.ts deleted file mode 100644 index f70568435..000000000 --- a/ecosystem-tests/nodenext-tsup/index.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { OpenAI } from 'openai'; - -const openai = new OpenAI(); - -function assertEqual(actual: any, expected: any) { - if (actual === expected) { - return; - } - - console.error('expected', expected); - console.error('actual ', actual); - throw new Error('expected values to be equal'); -} - -async function main() { - const completion = await openai.chat.completions.create({ - model: 'gpt-4o-mini', - messages: [ - { - role: 'user', - content: 'What is the capital of the United States?', - }, - ], - }); - // smoke test for responses - if (!completion.choices[0]?.message.content) { - console.dir(completion, { depth: 4 }); - throw new Error('no response content!'); - } - - assertEqual( - decodeURIComponent((openai as any).stringifyQuery({ foo: { nested: { a: true, b: 'foo' } } })), - 'foo[nested][a]=true&foo[nested][b]=foo', - ); - assertEqual( - decodeURIComponent((openai as any).stringifyQuery({ foo: { nested: { a: ['hello', 'world'] } } })), - 'foo[nested][a][]=hello&foo[nested][a][]=world', - ); -} - -main(); diff --git a/ecosystem-tests/nodenext-tsup/package-lock.json b/ecosystem-tests/nodenext-tsup/package-lock.json deleted file mode 100644 index 8f4729374..000000000 --- a/ecosystem-tests/nodenext-tsup/package-lock.json +++ /dev/null @@ -1,2078 +0,0 @@ -{ - "name": "nodenext-tsup", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "nodenext-tsup", - "devDependencies": { - "tsup": "^8.2.4" - }, - "peerDependencies": { - "typescript": "^5.5.4" - } - }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.23.1.tgz", - "integrity": "sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.23.1.tgz", - "integrity": "sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.23.1.tgz", - "integrity": "sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.23.1.tgz", - "integrity": "sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.23.1.tgz", - "integrity": "sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.23.1.tgz", - "integrity": "sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.23.1.tgz", - "integrity": "sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.23.1.tgz", - "integrity": "sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.23.1.tgz", - "integrity": "sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.23.1.tgz", - "integrity": "sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.23.1.tgz", - "integrity": "sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.23.1.tgz", - "integrity": "sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==", - "cpu": [ - "loong64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.23.1.tgz", - "integrity": "sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==", - "cpu": [ - "mips64el" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.23.1.tgz", - "integrity": "sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.23.1.tgz", - "integrity": "sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.23.1.tgz", - "integrity": "sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.23.1.tgz", - "integrity": "sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.23.1.tgz", - "integrity": "sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.23.1.tgz", - "integrity": "sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.23.1.tgz", - "integrity": "sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.23.1.tgz", - "integrity": "sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.23.1.tgz", - "integrity": "sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.23.1.tgz", - "integrity": "sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.23.1.tgz", - "integrity": "sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "dev": true, - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", - "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", - "dev": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "dev": true, - "optional": true, - "engines": { - "node": ">=14" - } - }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.21.2.tgz", - "integrity": "sha512-fSuPrt0ZO8uXeS+xP3b+yYTCBUd05MoSp2N/MFOgjhhUhMmchXlpTQrTpI8T+YAwAQuK7MafsCOxW7VrPMrJcg==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.21.2.tgz", - "integrity": "sha512-xGU5ZQmPlsjQS6tzTTGwMsnKUtu0WVbl0hYpTPauvbRAnmIvpInhJtgjj3mcuJpEiuUw4v1s4BimkdfDWlh7gA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.21.2.tgz", - "integrity": "sha512-99AhQ3/ZMxU7jw34Sq8brzXqWH/bMnf7ZVhvLk9QU2cOepbQSVTns6qoErJmSiAvU3InRqC2RRZ5ovh1KN0d0Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.21.2.tgz", - "integrity": "sha512-ZbRaUvw2iN/y37x6dY50D8m2BnDbBjlnMPotDi/qITMJ4sIxNY33HArjikDyakhSv0+ybdUxhWxE6kTI4oX26w==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.21.2.tgz", - "integrity": "sha512-ztRJJMiE8nnU1YFcdbd9BcH6bGWG1z+jP+IPW2oDUAPxPjo9dverIOyXz76m6IPA6udEL12reYeLojzW2cYL7w==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.21.2.tgz", - "integrity": "sha512-flOcGHDZajGKYpLV0JNc0VFH361M7rnV1ee+NTeC/BQQ1/0pllYcFmxpagltANYt8FYf9+kL6RSk80Ziwyhr7w==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.21.2.tgz", - "integrity": "sha512-69CF19Kp3TdMopyteO/LJbWufOzqqXzkrv4L2sP8kfMaAQ6iwky7NoXTp7bD6/irKgknDKM0P9E/1l5XxVQAhw==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.21.2.tgz", - "integrity": "sha512-48pD/fJkTiHAZTnZwR0VzHrao70/4MlzJrq0ZsILjLW/Ab/1XlVUStYyGt7tdyIiVSlGZbnliqmult/QGA2O2w==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.21.2.tgz", - "integrity": "sha512-cZdyuInj0ofc7mAQpKcPR2a2iu4YM4FQfuUzCVA2u4HI95lCwzjoPtdWjdpDKyHxI0UO82bLDoOaLfpZ/wviyQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.21.2.tgz", - "integrity": "sha512-RL56JMT6NwQ0lXIQmMIWr1SW28z4E4pOhRRNqwWZeXpRlykRIlEpSWdsgNWJbYBEWD84eocjSGDu/XxbYeCmwg==", - "cpu": [ - "riscv64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.21.2.tgz", - "integrity": "sha512-PMxkrWS9z38bCr3rWvDFVGD6sFeZJw4iQlhrup7ReGmfn7Oukrr/zweLhYX6v2/8J6Cep9IEA/SmjXjCmSbrMQ==", - "cpu": [ - "s390x" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.21.2.tgz", - "integrity": "sha512-B90tYAUoLhU22olrafY3JQCFLnT3NglazdwkHyxNDYF/zAxJt5fJUB/yBoWFoIQ7SQj+KLe3iL4BhOMa9fzgpw==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.21.2.tgz", - "integrity": "sha512-7twFizNXudESmC9oneLGIUmoHiiLppz/Xs5uJQ4ShvE6234K0VB1/aJYU3f/4g7PhssLGKBVCC37uRkkOi8wjg==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.21.2.tgz", - "integrity": "sha512-9rRero0E7qTeYf6+rFh3AErTNU1VCQg2mn7CQcI44vNUWM9Ze7MSRS/9RFuSsox+vstRt97+x3sOhEey024FRQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.21.2.tgz", - "integrity": "sha512-5rA4vjlqgrpbFVVHX3qkrCo/fZTj1q0Xxpg+Z7yIo3J2AilW7t2+n6Q8Jrx+4MrYpAnjttTYF8rr7bP46BPzRw==", - "cpu": [ - "ia32" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.21.2.tgz", - "integrity": "sha512-6UUxd0+SKomjdzuAcp+HAmxw1FlGBnl1v2yEPSabtx4lBfdXHDVsW7+lQkgz9cNFJGY3AWR7+V8P5BqkD9L9nA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@types/estree": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", - "dev": true - }, - "node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", - "dev": true - }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/bundle-require": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/bundle-require/-/bundle-require-5.0.0.tgz", - "integrity": "sha512-GuziW3fSSmopcx4KRymQEJVbZUfqlCqcq7dvs6TYwKRZiegK/2buMxQTPs6MGlNv50wms1699qYO54R8XfRX4w==", - "dev": true, - "dependencies": { - "load-tsconfig": "^0.2.3" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "peerDependencies": { - "esbuild": ">=0.18" - } - }, - "node_modules/cac": { - "version": "6.7.14", - "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", - "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dev": true, - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/consola": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/consola/-/consola-3.2.3.tgz", - "integrity": "sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ==", - "dev": true, - "engines": { - "node": "^14.18.0 || >=16.10.0" - } - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/debug": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.6.tgz", - "integrity": "sha512-O/09Bd4Z1fBrU4VzkhFqVgpPzaGbw6Sm9FEkBT1A/YBXQFGuuSxa1dN2nxgxS34JmKXqYx8CZAwEVoJFImUXIg==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/debug/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true - }, - "node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true - }, - "node_modules/esbuild": { - "version": "0.23.1", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.23.1.tgz", - "integrity": "sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==", - "dev": true, - "hasInstallScript": true, - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.23.1", - "@esbuild/android-arm": "0.23.1", - "@esbuild/android-arm64": "0.23.1", - "@esbuild/android-x64": "0.23.1", - "@esbuild/darwin-arm64": "0.23.1", - "@esbuild/darwin-x64": "0.23.1", - "@esbuild/freebsd-arm64": "0.23.1", - "@esbuild/freebsd-x64": "0.23.1", - "@esbuild/linux-arm": "0.23.1", - "@esbuild/linux-arm64": "0.23.1", - "@esbuild/linux-ia32": "0.23.1", - "@esbuild/linux-loong64": "0.23.1", - "@esbuild/linux-mips64el": "0.23.1", - "@esbuild/linux-ppc64": "0.23.1", - "@esbuild/linux-riscv64": "0.23.1", - "@esbuild/linux-s390x": "0.23.1", - "@esbuild/linux-x64": "0.23.1", - "@esbuild/netbsd-x64": "0.23.1", - "@esbuild/openbsd-arm64": "0.23.1", - "@esbuild/openbsd-x64": "0.23.1", - "@esbuild/sunos-x64": "0.23.1", - "@esbuild/win32-arm64": "0.23.1", - "@esbuild/win32-ia32": "0.23.1", - "@esbuild/win32-x64": "0.23.1" - } - }, - "node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/fast-glob": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", - "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fastq": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", - "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/foreground-child": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", - "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/foreground-child/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/glob": { - "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", - "dev": true, - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true, - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "node_modules/jackspeak": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", - "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", - "dev": true, - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" - } - }, - "node_modules/joycon": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz", - "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/lilconfig": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz", - "integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==", - "dev": true, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/antonk52" - } - }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true - }, - "node_modules/load-tsconfig": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/load-tsconfig/-/load-tsconfig-0.2.5.tgz", - "integrity": "sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==", - "dev": true, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - } - }, - "node_modules/lodash.sortby": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", - "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==", - "dev": true - }, - "node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "dev": true, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/mz": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", - "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", - "dev": true, - "dependencies": { - "any-promise": "^1.0.0", - "object-assign": "^4.0.1", - "thenify-all": "^1.0.0" - } - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/package-json-from-dist": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", - "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==", - "dev": true - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-scurry": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", - "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", - "dev": true, - "dependencies": { - "lru-cache": "^10.2.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" - }, - "engines": { - "node": ">=16 || 14 >=14.18" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/picocolors": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz", - "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==", - "dev": true - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pirates": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz", - "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/postcss-load-config": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", - "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "lilconfig": "^3.1.1" - }, - "engines": { - "node": ">= 18" - }, - "peerDependencies": { - "jiti": ">=1.21.0", - "postcss": ">=8.0.9", - "tsx": "^4.8.1", - "yaml": "^2.4.2" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - }, - "postcss": { - "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true - } - } - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rollup": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.21.2.tgz", - "integrity": "sha512-e3TapAgYf9xjdLvKQCkQTnbTKd4a6jwlpQSJJFokHGaX2IVjoEqkIIhiQfqsi0cdwlOD+tQGuOd5AJkc5RngBw==", - "dev": true, - "dependencies": { - "@types/estree": "1.0.5" - }, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.21.2", - "@rollup/rollup-android-arm64": "4.21.2", - "@rollup/rollup-darwin-arm64": "4.21.2", - "@rollup/rollup-darwin-x64": "4.21.2", - "@rollup/rollup-linux-arm-gnueabihf": "4.21.2", - "@rollup/rollup-linux-arm-musleabihf": "4.21.2", - "@rollup/rollup-linux-arm64-gnu": "4.21.2", - "@rollup/rollup-linux-arm64-musl": "4.21.2", - "@rollup/rollup-linux-powerpc64le-gnu": "4.21.2", - "@rollup/rollup-linux-riscv64-gnu": "4.21.2", - "@rollup/rollup-linux-s390x-gnu": "4.21.2", - "@rollup/rollup-linux-x64-gnu": "4.21.2", - "@rollup/rollup-linux-x64-musl": "4.21.2", - "@rollup/rollup-win32-arm64-msvc": "4.21.2", - "@rollup/rollup-win32-ia32-msvc": "4.21.2", - "@rollup/rollup-win32-x64-msvc": "4.21.2", - "fsevents": "~2.3.2" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/source-map": { - "version": "0.8.0-beta.0", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz", - "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==", - "dev": true, - "dependencies": { - "whatwg-url": "^7.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/source-map/node_modules/tr46": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", - "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/source-map/node_modules/webidl-conversions": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", - "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", - "dev": true - }, - "node_modules/source-map/node_modules/whatwg-url": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", - "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", - "dev": true, - "dependencies": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" - } - }, - "node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/string-width-cjs": { - "name": "string-width", - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width-cjs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width-cjs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/string-width-cjs/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/strip-ansi-cjs": { - "name": "strip-ansi", - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/sucrase": { - "version": "3.35.0", - "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", - "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", - "dev": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.2", - "commander": "^4.0.0", - "glob": "^10.3.10", - "lines-and-columns": "^1.1.6", - "mz": "^2.7.0", - "pirates": "^4.0.1", - "ts-interface-checker": "^0.1.9" - }, - "bin": { - "sucrase": "bin/sucrase", - "sucrase-node": "bin/sucrase-node" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/thenify": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", - "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", - "dev": true, - "dependencies": { - "any-promise": "^1.0.0" - } - }, - "node_modules/thenify-all": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", - "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", - "dev": true, - "dependencies": { - "thenify": ">= 3.1.0 < 4" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/tree-kill": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", - "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", - "dev": true, - "bin": { - "tree-kill": "cli.js" - } - }, - "node_modules/ts-interface-checker": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", - "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", - "dev": true - }, - "node_modules/tsup": { - "version": "8.2.4", - "resolved": "https://registry.npmjs.org/tsup/-/tsup-8.2.4.tgz", - "integrity": "sha512-akpCPePnBnC/CXgRrcy72ZSntgIEUa1jN0oJbbvpALWKNOz1B7aM+UVDWGRGIO/T/PZugAESWDJUAb5FD48o8Q==", - "dev": true, - "dependencies": { - "bundle-require": "^5.0.0", - "cac": "^6.7.14", - "chokidar": "^3.6.0", - "consola": "^3.2.3", - "debug": "^4.3.5", - "esbuild": "^0.23.0", - "execa": "^5.1.1", - "globby": "^11.1.0", - "joycon": "^3.1.1", - "picocolors": "^1.0.1", - "postcss-load-config": "^6.0.1", - "resolve-from": "^5.0.0", - "rollup": "^4.19.0", - "source-map": "0.8.0-beta.0", - "sucrase": "^3.35.0", - "tree-kill": "^1.2.2" - }, - "bin": { - "tsup": "dist/cli-default.js", - "tsup-node": "dist/cli-node.js" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@microsoft/api-extractor": "^7.36.0", - "@swc/core": "^1", - "postcss": "^8.4.12", - "typescript": ">=4.5.0" - }, - "peerDependenciesMeta": { - "@microsoft/api-extractor": { - "optional": true - }, - "@swc/core": { - "optional": true - }, - "postcss": { - "optional": true - }, - "typescript": { - "optional": true - } - } - }, - "node_modules/typescript": { - "version": "5.5.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz", - "integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==", - "peer": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs": { - "name": "wrap-ansi", - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/wrap-ansi-cjs/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - } - } -} diff --git a/ecosystem-tests/nodenext-tsup/package.json b/ecosystem-tests/nodenext-tsup/package.json deleted file mode 100644 index ddef80219..000000000 --- a/ecosystem-tests/nodenext-tsup/package.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "name": "nodenext-tsup", - "module": "index.ts", - "type": "module", - "scripts": { - "build": "tsup", - "main": "npm run build && node dist/index.cjs" - }, - "dependencies": {}, - "devDependencies": { - "tsup": "^8.2.4" - }, - "peerDependencies": { - "typescript": "^5.5.4" - } -} diff --git a/ecosystem-tests/nodenext-tsup/tsconfig.json b/ecosystem-tests/nodenext-tsup/tsconfig.json deleted file mode 100644 index 49111f4a1..000000000 --- a/ecosystem-tests/nodenext-tsup/tsconfig.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "compilerOptions": { - "declaration": true, - "declarationMap": true, - "esModuleInterop": true, - "incremental": false, - "isolatedModules": true, - "lib": ["es2022", "DOM", "DOM.Iterable"], - "module": "NodeNext", - "moduleDetection": "force", - "moduleResolution": "NodeNext", - "noUncheckedIndexedAccess": true, - "resolveJsonModule": true, - "skipLibCheck": true, - "strict": true, - "target": "ES2022" - } -} diff --git a/ecosystem-tests/nodenext-tsup/tsup.config.ts b/ecosystem-tests/nodenext-tsup/tsup.config.ts deleted file mode 100644 index 657cd79fa..000000000 --- a/ecosystem-tests/nodenext-tsup/tsup.config.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { defineConfig } from "tsup"; - -export default defineConfig({ - entry: ["index.ts"], - noExternal: ["openai"], - platform: "neutral", -}); diff --git a/ecosystem-tests/proxy.ts b/ecosystem-tests/proxy.ts new file mode 100644 index 000000000..ab05685a3 --- /dev/null +++ b/ecosystem-tests/proxy.ts @@ -0,0 +1,27 @@ +import { createServer } from 'http'; +import { connect } from 'net'; + +async function startProxy() { + const proxy = createServer((_req, res) => { + res.end(); + }); + + proxy.on('connect', (req, clientSocket, head) => { + const serverSocket = connect(443, 'api.openai.com', () => { + clientSocket.write( + 'HTTP/1.1 200 Connection Established\r\n' + 'Proxy-agent: Node.js-Proxy\r\n' + '\r\n', + ); + serverSocket.write(head); + serverSocket.pipe(clientSocket); + clientSocket.pipe(serverSocket); + }); + }); + + await new Promise((resolve) => proxy.listen(0, '127.0.0.1', resolve)); + + console.log(proxy.address()!.toString()) + + return () => { + proxy.close() + } +} diff --git a/ecosystem-tests/ts-browser-webpack/package-lock.json b/ecosystem-tests/ts-browser-webpack/package-lock.json index 695b85955..c04a9b959 100644 --- a/ecosystem-tests/ts-browser-webpack/package-lock.json +++ b/ecosystem-tests/ts-browser-webpack/package-lock.json @@ -3150,6 +3150,15 @@ "node": ">= 10.0" } }, + "node_modules/clean-css/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", @@ -3748,6 +3757,16 @@ "source-map": "~0.6.1" } }, + "node_modules/escodegen/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/eslint-scope": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", @@ -4776,6 +4795,12 @@ "node": ">= 12" } }, + "node_modules/ip-address/node_modules/jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", + "dev": true + }, "node_modules/ipaddr.js": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.1.0.tgz", @@ -5007,12 +5032,6 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/jsbn": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", - "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", - "dev": true - }, "node_modules/jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -6525,15 +6544,6 @@ "node": ">= 14" } }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/spdy": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", @@ -6816,6 +6826,15 @@ "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", "dev": true }, + "node_modules/terser/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/terser/node_modules/source-map-support": { "version": "0.5.21", "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", diff --git a/ecosystem-tests/ts-browser-webpack/src/index.ts b/ecosystem-tests/ts-browser-webpack/src/index.ts index 75fb6ea7a..9a01bdc30 100644 --- a/ecosystem-tests/ts-browser-webpack/src/index.ts +++ b/ecosystem-tests/ts-browser-webpack/src/index.ts @@ -1,4 +1,3 @@ -import 'openai/shims/web'; import OpenAI, { toFile } from 'openai'; import { distance } from 'fastest-levenshtein'; import { ChatCompletion } from 'openai/resources/chat/completions'; @@ -209,13 +208,4 @@ describe('toFile', () => { }); }); -it('handles query strings', () => { - expect( - decodeURIComponent((client as any).stringifyQuery({ foo: { nested: { a: true, b: 'foo' } } })), - ).toEqual('foo[nested][a]=true&foo[nested][b]=foo'); - expect( - decodeURIComponent((client as any).stringifyQuery({ foo: { nested: { a: ['hello', 'world'] } } })), - ).toEqual('foo[nested][a][]=hello&foo[nested][a][]=world'); -}); - runTests(); diff --git a/ecosystem-tests/vercel-edge/src/uploadWebApiTestCases.ts b/ecosystem-tests/vercel-edge/src/uploadWebApiTestCases.ts index eb8be0030..59ce5c49a 100644 --- a/ecosystem-tests/vercel-edge/src/uploadWebApiTestCases.ts +++ b/ecosystem-tests/vercel-edge/src/uploadWebApiTestCases.ts @@ -1,7 +1,6 @@ import OpenAI, { toFile } from 'openai'; import { TranscriptionCreateParams } from 'openai/resources/audio/transcriptions'; import { ChatCompletion } from 'openai/resources/chat/completions'; -import * as nf from 'node-fetch'; /** * Tests uploads using various Web API data objects. @@ -58,18 +57,18 @@ export function uploadWebApiTestCases({ }) .asResponse(); - // test that we can use node-fetch Response API + const decoder = new TextDecoder(); const chunks: string[] = []; - // we can't have both node and web response types in one project, - // but the tests will work at runtime because they will be in different - // enrivonments. So cast to any here - const { body } = response as any as nf.Response; - if (!body) throw new Error(`expected response.body to be defined`); - body.on('data', (chunk) => chunks.push(chunk)); - await new Promise((resolve, reject) => { - body.once('end', resolve); - body.once('error', reject); - }); + + // We need to cast to any as we're using both node types and web types. + // This works with the node types but to get this to work with web types + // we would need to bump `typescript` to ~5.5 and add `DOM.AsyncIterable` + // to `lib` but we want to test older ts versions + const body = response.body! as any; + for await (const chunk of body) { + chunks.push(decoder.decode(chunk)); + } + const json: ChatCompletion = JSON.parse(chunks.join('')); expectSimilar(json.choices[0]?.message.content || '', 'This is a test', 10); }); @@ -180,15 +179,4 @@ export function uploadWebApiTestCases({ expectEqual(result.filename, 'finetune.jsonl'); }); } - - it('handles query strings', async () => { - expectEqual( - decodeURIComponent((client as any).stringifyQuery({ foo: { nested: { a: true, b: 'foo' } } })), - 'foo[nested][a]=true&foo[nested][b]=foo', - ); - expectEqual( - decodeURIComponent((client as any).stringifyQuery({ foo: { nested: { a: ['hello', 'world'] } } })), - 'foo[nested][a][]=hello&foo[nested][a][]=world', - ); - }); } diff --git a/ecosystem-tests/vercel-edge/tests/test.ts b/ecosystem-tests/vercel-edge/tests/test.ts index 36a7ea0bf..02414ff7b 100644 --- a/ecosystem-tests/vercel-edge/tests/test.ts +++ b/ecosystem-tests/vercel-edge/tests/test.ts @@ -1,5 +1,3 @@ -import fetch from 'node-fetch'; - const baseUrl = process.env.TEST_BASE_URL || 'http://localhost:3000/'; console.log(baseUrl); @@ -18,3 +16,6 @@ it( }, 3 * 60000, ); + +// make isolatedModules happy +export {}; diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 000000000..e44b82f24 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,42 @@ +// @ts-check +import tseslint from 'typescript-eslint'; +import unusedImports from 'eslint-plugin-unused-imports'; +import prettier from 'eslint-plugin-prettier'; + +export default tseslint.config( + { + languageOptions: { + parser: tseslint.parser, + parserOptions: { sourceType: 'module' }, + }, + files: ['**/*.ts', '**/*.mts', '**/*.cts', '**/*.js', '**/*.mjs', '**/*.cjs'], + ignores: ['dist/**', 'ecosystem-tests/**'], + plugins: { + '@typescript-eslint': tseslint.plugin, + 'unused-imports': unusedImports, + prettier, + }, + rules: { + 'no-unused-vars': 'off', + 'prettier/prettier': 'error', + 'unused-imports/no-unused-imports': 'error', + 'no-restricted-imports': [ + 'error', + { + patterns: [ + { + regex: '^openai(/.*)?', + message: 'Use a relative import, not a package import.', + }, + ], + }, + ], + }, + }, + { + files: ['tests/**', 'examples/**'], + rules: { + 'no-restricted-imports': 'off', + }, + }, +); diff --git a/examples/audio.ts b/examples/audio.ts index a37c93b20..1903aa184 100755 --- a/examples/audio.ts +++ b/examples/audio.ts @@ -1,5 +1,4 @@ #!/usr/bin/env -S npm run tsn -T -import 'openai/shims/node'; import OpenAI, { toFile } from 'openai'; import fs from 'fs'; @@ -23,9 +22,10 @@ async function streamingDemoNode() { input: 'the quick brown chicken jumped over the lazy dogs', }); - const stream = response.body; + const stream = response.body!; console.log(`Streaming response to ${speechFile}`); + // @ts-ignore await streamToFile(stream, speechFile); console.log('Finished streaming'); } diff --git a/examples/azure.ts b/examples/azure/chat.ts similarity index 91% rename from examples/azure.ts rename to examples/azure/chat.ts index 5fe1718fa..46df820f8 100755 --- a/examples/azure.ts +++ b/examples/azure/chat.ts @@ -2,6 +2,7 @@ import { AzureOpenAI } from 'openai'; import { getBearerTokenProvider, DefaultAzureCredential } from '@azure/identity'; +import 'dotenv/config'; // Corresponds to your Model deployment within your OpenAI resource, e.g. gpt-4-1106-preview // Navigate to the Azure OpenAI Studio to deploy a model. @@ -13,7 +14,7 @@ const azureADTokenProvider = getBearerTokenProvider(credential, scope); // Make sure to set AZURE_OPENAI_ENDPOINT with the endpoint of your Azure resource. // You can find it in the Azure Portal. -const openai = new AzureOpenAI({ azureADTokenProvider }); +const openai = new AzureOpenAI({ azureADTokenProvider, apiVersion: '2024-10-01-preview' }); async function main() { console.log('Non-streaming:'); diff --git a/examples/azure/realtime/websocket.ts b/examples/azure/realtime/websocket.ts new file mode 100644 index 000000000..bec74e654 --- /dev/null +++ b/examples/azure/realtime/websocket.ts @@ -0,0 +1,60 @@ +import { OpenAIRealtimeWebSocket } from 'openai/beta/realtime/websocket'; +import { AzureOpenAI } from 'openai'; +import { DefaultAzureCredential, getBearerTokenProvider } from '@azure/identity'; +import 'dotenv/config'; + +async function main() { + const cred = new DefaultAzureCredential(); + const scope = 'https://cognitiveservices.azure.com/.default'; + const deploymentName = 'gpt-4o-realtime-preview-1001'; + const azureADTokenProvider = getBearerTokenProvider(cred, scope); + const client = new AzureOpenAI({ + azureADTokenProvider, + apiVersion: '2024-10-01-preview', + deployment: deploymentName, + }); + const rt = await OpenAIRealtimeWebSocket.azure(client); + + // access the underlying `ws.WebSocket` instance + rt.socket.addEventListener('open', () => { + console.log('Connection opened!'); + rt.send({ + type: 'session.update', + session: { + modalities: ['text'], + model: 'gpt-4o-realtime-preview', + }, + }); + + rt.send({ + type: 'conversation.item.create', + item: { + type: 'message', + role: 'user', + content: [{ type: 'input_text', text: 'Say a couple paragraphs!' }], + }, + }); + + rt.send({ type: 'response.create' }); + }); + + rt.on('error', (err) => { + // in a real world scenario this should be logged somewhere as you + // likely want to continue procesing events regardless of any errors + throw err; + }); + + rt.on('session.created', (event) => { + console.log('session created!', event.session); + console.log(); + }); + + rt.on('response.text.delta', (event) => process.stdout.write(event.delta)); + rt.on('response.text.done', () => console.log()); + + rt.on('response.done', () => rt.close()); + + rt.socket.addEventListener('close', () => console.log('\nConnection closed!')); +} + +main(); diff --git a/examples/azure/realtime/ws.ts b/examples/azure/realtime/ws.ts new file mode 100644 index 000000000..6ab7b742a --- /dev/null +++ b/examples/azure/realtime/ws.ts @@ -0,0 +1,60 @@ +import { DefaultAzureCredential, getBearerTokenProvider } from '@azure/identity'; +import { OpenAIRealtimeWS } from 'openai/beta/realtime/ws'; +import { AzureOpenAI } from 'openai'; +import 'dotenv/config'; + +async function main() { + const cred = new DefaultAzureCredential(); + const scope = 'https://cognitiveservices.azure.com/.default'; + const deploymentName = 'gpt-4o-realtime-preview-1001'; + const azureADTokenProvider = getBearerTokenProvider(cred, scope); + const client = new AzureOpenAI({ + azureADTokenProvider, + apiVersion: '2024-10-01-preview', + deployment: deploymentName, + }); + const rt = await OpenAIRealtimeWS.azure(client); + + // access the underlying `ws.WebSocket` instance + rt.socket.on('open', () => { + console.log('Connection opened!'); + rt.send({ + type: 'session.update', + session: { + modalities: ['text'], + model: 'gpt-4o-realtime-preview', + }, + }); + + rt.send({ + type: 'conversation.item.create', + item: { + type: 'message', + role: 'user', + content: [{ type: 'input_text', text: 'Say a couple paragraphs!' }], + }, + }); + + rt.send({ type: 'response.create' }); + }); + + rt.on('error', (err) => { + // in a real world scenario this should be logged somewhere as you + // likely want to continue procesing events regardless of any errors + throw err; + }); + + rt.on('session.created', (event) => { + console.log('session created!', event.session); + console.log(); + }); + + rt.on('response.text.delta', (event) => process.stdout.write(event.delta)); + rt.on('response.text.done', () => console.log()); + + rt.on('response.done', () => rt.close()); + + rt.socket.on('close', () => console.log('\nConnection closed!')); +} + +main(); diff --git a/examples/function-call-helpers-zod.ts b/examples/function-call-helpers-zod.ts deleted file mode 100755 index f783aee08..000000000 --- a/examples/function-call-helpers-zod.ts +++ /dev/null @@ -1,112 +0,0 @@ -#!/usr/bin/env -S npm run tsn -T - -import OpenAI from 'openai'; -import { ZodSchema, z } from 'zod'; -import { zodToJsonSchema } from 'zod-to-json-schema'; - -const openai = new OpenAI(); - -const ListParams = z.object({ - genre: z.enum(['mystery', 'nonfiction', 'memoir', 'romance', 'historical']), -}); - -const SearchParams = z.object({ - name: z.string(), -}); - -const GetParams = z.object({ - id: z.string(), -}); - -const functions = [ - { - name: 'list', - description: 'list queries books by genre, and returns a list of names of books', - parameters: zodToJsonSchema(ListParams), - parse: zodParseJSON(ListParams), - function: list, - }, - { - name: 'search', - description: 'search queries books by their name and returns a list of book names and their ids', - parameters: zodToJsonSchema(SearchParams), - parse: zodParseJSON(SearchParams), - function: search, - }, - { - name: 'get', - description: - "get returns a book's detailed information based on the id of the book. Note that this does not accept names, and only IDs, which you can get by using search.", - parameters: zodToJsonSchema(GetParams), - parse: zodParseJSON(GetParams), - function: get, - }, -] as const; - -async function main() { - const runner = await openai.beta.chat.completions - .runFunctions({ - model: 'gpt-3.5-turbo', - messages: [ - { - role: 'system', - content: - 'Please use our book database, which you can access using functions to answer the following questions.', - }, - { - role: 'user', - content: - 'I really enjoyed reading To Kill a Mockingbird, could you recommend me a book that is similar and tell me why?', - }, - ], - functions, - }) - .on('message', (msg) => console.log(msg)) - .on('content', (diff) => process.stdout.write(diff)); - - const result = await runner.finalChatCompletion(); - console.log(result); - - console.log(); - console.log(runner.messages); -} - -const db = [ - { - id: 'a1', - name: 'To Kill a Mockingbird', - genre: 'historical', - description: `Compassionate, dramatic, and deeply moving, "To Kill A Mockingbird" takes readers to the roots of human behavior - to innocence and experience, kindness and cruelty, love and hatred, humor and pathos. Now with over 18 million copies in print and translated into forty languages, this regional story by a young Alabama woman claims universal appeal. Harper Lee always considered her book to be a simple love story. Today it is regarded as a masterpiece of American literature.`, - }, - { - id: 'a2', - name: 'All the Light We Cannot See', - genre: 'historical', - description: `In a mining town in Germany, Werner Pfennig, an orphan, grows up with his younger sister, enchanted by a crude radio they find that brings them news and stories from places they have never seen or imagined. Werner becomes an expert at building and fixing these crucial new instruments and is enlisted to use his talent to track down the resistance. Deftly interweaving the lives of Marie-Laure and Werner, Doerr illuminates the ways, against all odds, people try to be good to one another.`, - }, - { - id: 'a3', - name: 'Where the Crawdads Sing', - genre: 'historical', - description: `For years, rumors of the “Marsh Girl” haunted Barkley Cove, a quiet fishing village. Kya Clark is barefoot and wild; unfit for polite society. So in late 1969, when the popular Chase Andrews is found dead, locals immediately suspect her. -But Kya is not what they say. A born naturalist with just one day of school, she takes life's lessons from the land, learning the real ways of the world from the dishonest signals of fireflies. But while she has the skills to live in solitude forever, the time comes when she yearns to be touched and loved. Drawn to two young men from town, who are each intrigued by her wild beauty, Kya opens herself to a new and startling world—until the unthinkable happens.`, - }, -]; - -async function list({ genre }: z.infer) { - return db.filter((item) => item.genre === genre).map((item) => ({ name: item.name, id: item.id })); -} - -async function search({ name }: z.infer) { - return db.filter((item) => item.name.includes(name)).map((item) => ({ name: item.name, id: item.id })); -} - -async function get({ id }: z.infer) { - return db.find((item) => item.id === id)!; -} - -function zodParseJSON(schema: ZodSchema) { - return (input: string): T => schema.parse(JSON.parse(input)); -} - -main(); diff --git a/examples/function-call-helpers.ts b/examples/function-call-helpers.ts deleted file mode 100755 index 48e2afd62..000000000 --- a/examples/function-call-helpers.ts +++ /dev/null @@ -1,110 +0,0 @@ -#!/usr/bin/env -S npm run tsn -T - -import OpenAI from 'openai'; - -// gets API Key from environment variable OPENAI_API_KEY -const openai = new OpenAI(); - -const functions = [ - { - name: 'list', - description: 'list queries books by genre, and returns a list of names of books', - parameters: { - type: 'object', - properties: { - genre: { type: 'string', enum: ['mystery', 'nonfiction', 'memoir', 'romance', 'historical'] }, - }, - }, - function: list, - parse: JSON.parse, - }, - { - name: 'search', - description: 'search queries books by their name and returns a list of book names and their ids', - parameters: { - type: 'object', - properties: { - name: { type: 'string' }, - }, - }, - function: search, - parse: JSON.parse, - }, - { - name: 'get', - description: - "get returns a book's detailed information based on the id of the book. Note that this does not accept names, and only IDs, which you can get by using search.", - parameters: { - type: 'object', - properties: { - id: { type: 'string' }, - }, - }, - function: get, - parse: JSON.parse, - }, -]; - -async function main() { - const runner = await openai.beta.chat.completions - .runFunctions({ - model: 'gpt-3.5-turbo', - messages: [ - { - role: 'system', - content: - 'Please use our book database, which you can access using functions to answer the following questions.', - }, - { - role: 'user', - content: - 'I really enjoyed reading To Kill a Mockingbird, could you recommend me a book that is similar and tell me why?', - }, - ], - functions, - }) - .on('message', (msg) => console.log(msg)) - .on('content', (diff) => process.stdout.write(diff)); - - const result = await runner.finalChatCompletion(); - console.log(result); - - console.log(); - console.log(runner.messages); -} - -const db = [ - { - id: 'a1', - name: 'To Kill a Mockingbird', - genre: 'historical', - description: `Compassionate, dramatic, and deeply moving, "To Kill A Mockingbird" takes readers to the roots of human behavior - to innocence and experience, kindness and cruelty, love and hatred, humor and pathos. Now with over 18 million copies in print and translated into forty languages, this regional story by a young Alabama woman claims universal appeal. Harper Lee always considered her book to be a simple love story. Today it is regarded as a masterpiece of American literature.`, - }, - { - id: 'a2', - name: 'All the Light We Cannot See', - genre: 'historical', - description: `In a mining town in Germany, Werner Pfennig, an orphan, grows up with his younger sister, enchanted by a crude radio they find that brings them news and stories from places they have never seen or imagined. Werner becomes an expert at building and fixing these crucial new instruments and is enlisted to use his talent to track down the resistance. Deftly interweaving the lives of Marie-Laure and Werner, Doerr illuminates the ways, against all odds, people try to be good to one another.`, - }, - { - id: 'a3', - name: 'Where the Crawdads Sing', - genre: 'historical', - description: `For years, rumors of the “Marsh Girl” haunted Barkley Cove, a quiet fishing village. Kya Clark is barefoot and wild; unfit for polite society. So in late 1969, when the popular Chase Andrews is found dead, locals immediately suspect her. -But Kya is not what they say. A born naturalist with just one day of school, she takes life's lessons from the land, learning the real ways of the world from the dishonest signals of fireflies. But while she has the skills to live in solitude forever, the time comes when she yearns to be touched and loved. Drawn to two young men from town, who are each intrigued by her wild beauty, Kya opens herself to a new and startling world—until the unthinkable happens.`, - }, -]; - -async function list({ genre }: { genre: string }) { - return db.filter((item) => item.genre === genre).map((item) => ({ name: item.name, id: item.id })); -} - -async function search({ name }: { name: string }) { - return db.filter((item) => item.name.includes(name)).map((item) => ({ name: item.name, id: item.id })); -} - -async function get({ id }: { id: string }) { - return db.find((item) => item.id === id)!; -} - -main(); diff --git a/examples/package.json b/examples/package.json index c8a5f7087..65b3216b2 100644 --- a/examples/package.json +++ b/examples/package.json @@ -6,6 +6,8 @@ "license": "MIT", "private": true, "dependencies": { + "@azure/identity": "^4.2.0", + "dotenv": "^16.4.7", "express": "^4.18.2", "next": "^14.1.1", "openai": "file:..", @@ -14,6 +16,7 @@ }, "devDependencies": { "@types/body-parser": "^1.19.3", - "@types/express": "^4.17.19" + "@types/express": "^4.17.19", + "@types/web": "^0.0.194" } } diff --git a/examples/realtime/websocket.ts b/examples/realtime/websocket.ts new file mode 100644 index 000000000..0da131bc3 --- /dev/null +++ b/examples/realtime/websocket.ts @@ -0,0 +1,48 @@ +import { OpenAIRealtimeWebSocket } from 'openai/beta/realtime/websocket'; + +async function main() { + const rt = new OpenAIRealtimeWebSocket({ model: 'gpt-4o-realtime-preview-2024-12-17' }); + + // access the underlying `ws.WebSocket` instance + rt.socket.addEventListener('open', () => { + console.log('Connection opened!'); + rt.send({ + type: 'session.update', + session: { + modalities: ['text'], + model: 'gpt-4o-realtime-preview', + }, + }); + + rt.send({ + type: 'conversation.item.create', + item: { + type: 'message', + role: 'user', + content: [{ type: 'input_text', text: 'Say a couple paragraphs!' }], + }, + }); + + rt.send({ type: 'response.create' }); + }); + + rt.on('error', (err) => { + // in a real world scenario this should be logged somewhere as you + // likely want to continue procesing events regardless of any errors + throw err; + }); + + rt.on('session.created', (event) => { + console.log('session created!', event.session); + console.log(); + }); + + rt.on('response.text.delta', (event) => process.stdout.write(event.delta)); + rt.on('response.text.done', () => console.log()); + + rt.on('response.done', () => rt.close()); + + rt.socket.addEventListener('close', () => console.log('\nConnection closed!')); +} + +main(); diff --git a/examples/realtime/ws.ts b/examples/realtime/ws.ts new file mode 100644 index 000000000..08c6fbcb6 --- /dev/null +++ b/examples/realtime/ws.ts @@ -0,0 +1,48 @@ +import { OpenAIRealtimeWS } from 'openai/beta/realtime/ws'; + +async function main() { + const rt = new OpenAIRealtimeWS({ model: 'gpt-4o-realtime-preview-2024-12-17' }); + + // access the underlying `ws.WebSocket` instance + rt.socket.on('open', () => { + console.log('Connection opened!'); + rt.send({ + type: 'session.update', + session: { + modalities: ['text'], + model: 'gpt-4o-realtime-preview', + }, + }); + + rt.send({ + type: 'conversation.item.create', + item: { + type: 'message', + role: 'user', + content: [{ type: 'input_text', text: 'Say a couple paragraphs!' }], + }, + }); + + rt.send({ type: 'response.create' }); + }); + + rt.on('error', (err) => { + // in a real world scenario this should be logged somewhere as you + // likely want to continue procesing events regardless of any errors + throw err; + }); + + rt.on('session.created', (event) => { + console.log('session created!', event.session); + console.log(); + }); + + rt.on('response.text.delta', (event) => process.stdout.write(event.delta)); + rt.on('response.text.done', () => console.log()); + + rt.on('response.done', () => rt.close()); + + rt.socket.on('close', () => console.log('\nConnection closed!')); +} + +main(); diff --git a/examples/stream-to-client-browser.ts b/examples/stream-to-client-browser.ts index 4430ccc68..4d9697505 100755 --- a/examples/stream-to-client-browser.ts +++ b/examples/stream-to-client-browser.ts @@ -5,10 +5,8 @@ * for easy demo purposes, but simulating use in the browser. * * To run it in a browser application, copy/paste it into a frontend application, - * remove the 'node-fetch' import, and replace `process.stdout.write` with - * a console.log or UI display. + * and replace `process.stdout.write` with a console.log or UI display. */ -import fetch from 'node-fetch'; import { ChatCompletionStream } from 'openai/lib/ChatCompletionStream'; fetch('http://github.com/service/http://localhost:3000/', { diff --git a/examples/tool-call-helpers-zod.ts b/examples/tool-call-helpers-zod.ts index 700f401a6..0d31b4933 100755 --- a/examples/tool-call-helpers-zod.ts +++ b/examples/tool-call-helpers-zod.ts @@ -1,10 +1,8 @@ #!/usr/bin/env -S npm run tsn -T import OpenAI from 'openai'; -import { RunnableToolFunctionWithParse } from 'openai/lib/RunnableFunction'; -import { JSONSchema } from 'openai/lib/jsonschema'; -import { ZodSchema, z } from 'zod'; -import { zodToJsonSchema } from 'zod-to-json-schema'; +import { zodFunction } from 'openai/helpers/zod'; +import { z } from 'zod'; // gets API Key from environment variable OPENAI_API_KEY const openai = new OpenAI(); @@ -42,18 +40,21 @@ async function main() { stream: true, tools: [ zodFunction({ + name: 'listBooks', function: listBooks, - schema: ListParams, + parameters: ListParams, description: 'List queries books by genre, and returns a list of names of books', }), zodFunction({ + name: 'searchBooks', function: searchBooks, - schema: SearchParams, + parameters: SearchParams, description: 'Search queries books by their name and returns a list of book names and their ids', }), zodFunction({ + name: 'getBook', function: getBook, - schema: GetParams, + parameters: GetParams, description: "Get returns a book's detailed information based on the id of the book. Note that this does not accept names, and only IDs, which you can get by using search.", }), @@ -108,37 +109,4 @@ But Kya is not what they say. A born naturalist with just one day of school, she }, ]; -/** - * A generic utility function that returns a RunnableFunction - * you can pass to `.runTools()`, - * with a fully validated, typesafe parameters schema. - * - * You are encouraged to copy/paste this into your codebase! - */ -function zodFunction({ - function: fn, - schema, - description = '', - name, -}: { - function: (args: T) => Promise; - schema: ZodSchema; - description?: string; - name?: string; -}): RunnableToolFunctionWithParse { - return { - type: 'function', - function: { - function: fn, - name: name ?? fn.name, - description: description, - parameters: zodToJsonSchema(schema) as JSONSchema, - parse(input: string): T { - const obj = JSON.parse(input); - return schema.parse(obj); - }, - }, - }; -} - main(); diff --git a/examples/types.ts b/examples/types.ts index 482e1f6be..e9de3911c 100755 --- a/examples/types.ts +++ b/examples/types.ts @@ -7,7 +7,7 @@ const openai = new OpenAI(); async function main() { // Explicit non streaming params type: - const params: OpenAI.Chat.CompletionCreateParams = { + const params: OpenAI.Chat.ChatCompletionCreateParams = { model: 'gpt-4', messages: [{ role: 'user', content: 'Say this is a test!' }], }; @@ -15,7 +15,7 @@ async function main() { console.log(completion.choices[0]?.message?.content); // Explicit streaming params type: - const streaming_params: OpenAI.Chat.CompletionCreateParams = { + const streaming_params: OpenAI.Chat.ChatCompletionCreateParams = { model: 'gpt-4', messages: [{ role: 'user', content: 'Say this is a test!' }], stream: true, diff --git a/helpers.md b/helpers.md index abf980c82..f66ebb39c 100644 --- a/helpers.md +++ b/helpers.md @@ -49,7 +49,7 @@ if (message?.parsed) { The `.parse()` method will also automatically parse `function` tool calls if: -- You use the `zodFunctionTool()` helper method +- You use the `zodFunction()` helper method - You mark your tool schema with `"strict": True` For example: @@ -226,7 +226,7 @@ on in the documentation page [Message](https://platform.openai.com/docs/api-refe ```ts .on('textCreated', (content: Text) => ...) -.on('textDelta', (delta: RunStepDelta, snapshot: Text) => ...) +.on('textDelta', (delta: TextDelta, snapshot: Text) => ...) .on('textDone', (content: Text, snapshot: Message) => ...) ``` @@ -353,8 +353,6 @@ chat completion request, not for the entire call run. See an example of automated function calls in action in [`examples/function-call-helpers.ts`](examples/function-call-helpers.ts). -Note, `runFunctions` was also previously available, but has been deprecated in favor of `runTools`. - ### Chat Events #### `.on('connect', () => …)` diff --git a/jest.config.ts b/jest.config.ts index aa2853fd2..ed3ba8754 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -8,7 +8,6 @@ const config: JestConfigWithTsJest = { }, moduleNameMapper: { '^openai$': '/src/index.ts', - '^openai/_shims/auto/(.*)$': '/src/_shims/auto/$1-node', '^openai/(.*)$': '/src/$1', }, modulePathIgnorePatterns: [ @@ -18,7 +17,7 @@ const config: JestConfigWithTsJest = { '/deno_tests/', ], testPathIgnorePatterns: ['scripts'], - prettierPath: require.resolve('prettier-2'), + // prettierPath: require.resolve('prettier-2'), }; export default config; diff --git a/jsr.json b/jsr.json index d76a2040e..dca12b1ff 100644 --- a/jsr.json +++ b/jsr.json @@ -1,7 +1,14 @@ { "name": "@openai/openai", - "version": "4.77.0", - "exports": "./index.ts", + "version": "5.0.0-alpha.0", + "exports": { + ".": "./index.ts", + "./helpers/zod": "./helpers/zod.ts", + "./beta/realtime/websocket": "./beta/realtime/websocket.ts" + }, + "imports": { + "zod": "npm:zod@3" + }, "publish": { "exclude": [ "!." diff --git a/package.json b/package.json index 54633aa5d..15e5c4143 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "openai", - "version": "4.77.0", + "version": "5.0.0-beta.0", "description": "The official TypeScript library for the OpenAI API", "author": "OpenAI ", "types": "dist/index.d.ts", @@ -23,112 +23,66 @@ "lint": "./scripts/lint", "fix": "./scripts/format" }, - "dependencies": { - "@types/node": "^18.11.18", - "@types/node-fetch": "^2.6.4", - "abort-controller": "^3.0.0", - "agentkeepalive": "^4.2.1", - "form-data-encoder": "1.7.2", - "formdata-node": "^4.3.2", - "node-fetch": "^2.6.7" - }, + "dependencies": {}, "devDependencies": { + "@arethetypeswrong/cli": "^0.17.0", "@swc/core": "^1.3.102", "@swc/jest": "^0.2.29", "@types/jest": "^29.4.0", - "@typescript-eslint/eslint-plugin": "^6.7.0", - "@typescript-eslint/parser": "^6.7.0", - "eslint": "^8.49.0", - "eslint-plugin-prettier": "^5.0.1", - "eslint-plugin-unused-imports": "^3.0.0", + "@types/ws": "^8.5.13", + "@types/node": "^20.17.6", + "typescript-eslint": "^8.24.0", + "@typescript-eslint/eslint-plugin": "^8.24.0", + "@typescript-eslint/parser": "^8.24.0", + "eslint": "^9.20.1", + "eslint-plugin-prettier": "^5.2.3", + "eslint-plugin-unused-imports": "^4.1.4", + "execa": "^5.1.1", "fast-check": "^3.22.0", "iconv-lite": "^0.6.3", "jest": "^29.4.0", "prettier": "^3.0.0", - "prettier-2": "npm:prettier@^2", - "segfault-handler": "^1.3.0", + "publint": "^0.2.12", "ts-jest": "^29.1.0", "ts-node": "^10.5.0", - "tsc-multi": "^1.1.0", + "tsc-multi": "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.3/tsc-multi.tgz", "tsconfig-paths": "^4.0.0", "typescript": "^4.8.2", + "ws": "^8.18.0", "zod": "^3.23.8" }, - "sideEffects": [ - "./_shims/index.js", - "./_shims/index.mjs", - "./shims/node.js", - "./shims/node.mjs", - "./shims/web.js", - "./shims/web.mjs" - ], + "resolutions": { + "synckit": "0.8.8" + }, "imports": { "openai": ".", "openai/*": "./src/*" }, "exports": { - "./_shims/auto/*": { - "deno": { - "types": "./dist/_shims/auto/*.d.ts", - "require": "./dist/_shims/auto/*.js", - "default": "./dist/_shims/auto/*.mjs" - }, - "bun": { - "types": "./dist/_shims/auto/*.d.ts", - "require": "./dist/_shims/auto/*-bun.js", - "default": "./dist/_shims/auto/*-bun.mjs" - }, - "browser": { - "types": "./dist/_shims/auto/*.d.ts", - "require": "./dist/_shims/auto/*.js", - "default": "./dist/_shims/auto/*.mjs" - }, - "worker": { - "types": "./dist/_shims/auto/*.d.ts", - "require": "./dist/_shims/auto/*.js", - "default": "./dist/_shims/auto/*.mjs" - }, - "workerd": { - "types": "./dist/_shims/auto/*.d.ts", - "require": "./dist/_shims/auto/*.js", - "default": "./dist/_shims/auto/*.mjs" - }, - "node": { - "types": "./dist/_shims/auto/*-node.d.ts", - "require": "./dist/_shims/auto/*-node.js", - "default": "./dist/_shims/auto/*-node.mjs" - }, - "types": "./dist/_shims/auto/*.d.ts", - "require": "./dist/_shims/auto/*.js", - "default": "./dist/_shims/auto/*.mjs" - }, ".": { - "require": { - "types": "./dist/index.d.ts", - "default": "./dist/index.js" - }, - "types": "./dist/index.d.mts", - "default": "./dist/index.mjs" + "import": "./dist/index.mjs", + "require": "./dist/index.js" }, "./*.mjs": { - "types": "./dist/*.d.ts", "default": "./dist/*.mjs" }, "./*.js": { - "types": "./dist/*.d.ts", "default": "./dist/*.js" }, "./*": { - "types": "./dist/*.d.ts", - "require": "./dist/*.js", - "default": "./dist/*.mjs" + "import": "./dist/*.mjs", + "require": "./dist/*.js" } }, "bin": "./bin/cli", "peerDependencies": { + "ws": "^8.18.0", "zod": "^3.23.8" }, "peerDependenciesMeta": { + "ws": { + "optional": true + }, "zod": { "optional": true } diff --git a/realtime.md b/realtime.md new file mode 100644 index 000000000..339dfd847 --- /dev/null +++ b/realtime.md @@ -0,0 +1,86 @@ +## Realtime API beta + +The Realtime API enables you to build low-latency, multi-modal conversational experiences. It currently supports text and audio as both input and output, as well as [function calling](https://platform.openai.com/docs/guides/function-calling) through a `WebSocket` connection. + +The Realtime API works through a combination of client-sent events and server-sent events. Clients can send events to do things like update session configuration or send text and audio inputs. Server events confirm when audio responses have completed, or when a text response from the model has been received. A full event reference can be found [here](https://platform.openai.com/docs/api-reference/realtime-client-events) and a guide can be found [here](https://platform.openai.com/docs/guides/realtime). + +This SDK supports accessing the Realtime API through the [WebSocket API](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket) or with [ws](https://github.com/websockets/ws). + +Basic text based example with `ws`: + +```ts +// requires `yarn add ws @types/ws` +import { OpenAIRealtimeWS } from 'openai/beta/realtime/ws'; + +const rt = new OpenAIRealtimeWS({ model: 'gpt-4o-realtime-preview-2024-12-17' }); + +// access the underlying `ws.WebSocket` instance +rt.socket.on('open', () => { + console.log('Connection opened!'); + rt.send({ + type: 'session.update', + session: { + modalities: ['text'], + model: 'gpt-4o-realtime-preview', + }, + }); + + rt.send({ + type: 'conversation.item.create', + item: { + type: 'message', + role: 'user', + content: [{ type: 'input_text', text: 'Say a couple paragraphs!' }], + }, + }); + + rt.send({ type: 'response.create' }); +}); + +rt.on('error', (err) => { + // in a real world scenario this should be logged somewhere as you + // likely want to continue procesing events regardless of any errors + throw err; +}); + +rt.on('session.created', (event) => { + console.log('session created!', event.session); + console.log(); +}); + +rt.on('response.text.delta', (event) => process.stdout.write(event.delta)); +rt.on('response.text.done', () => console.log()); + +rt.on('response.done', () => rt.close()); + +rt.socket.on('close', () => console.log('\nConnection closed!')); +``` + +To use the web API `WebSocket` implementation, replace `OpenAIRealtimeWS` with `OpenAIRealtimeWebSocket` and adjust any `rt.socket` access: + +```ts +import { OpenAIRealtimeWebSocket } from 'openai/beta/realtime/websocket'; + +const rt = new OpenAIRealtimeWebSocket({ model: 'gpt-4o-realtime-preview-2024-12-17' }); +// ... +rt.socket.addEventListener('open', () => { + // ... +}); +``` + +A full example can be found [here](https://github.com/openai/openai-node/blob/master/examples/realtime/websocket.ts). + +### Realtime error handling + +When an error is encountered, either on the client side or returned from the server through the [`error` event](https://platform.openai.com/docs/guides/realtime-model-capabilities#error-handling), the `error` event listener will be fired. However, if you haven't registered an `error` event listener then an `unhandled Promise rejection` error will be thrown. + +It is **highly recommended** that you register an `error` event listener and handle errors approriately as typically the underlying connection is still usable. + +```ts +const rt = new OpenAIRealtimeWS({ model: 'gpt-4o-realtime-preview-2024-12-17' }); +rt.on('error', (err) => { + // in a real world scenario this should be logged somewhere as you + // likely want to continue procesing events regardless of any errors + throw err; +}); +``` diff --git a/scripts/build b/scripts/build index 4e86f99e2..dd2c9dd57 100755 --- a/scripts/build +++ b/scripts/build @@ -15,7 +15,6 @@ rm -rf dist; mkdir dist # Copy src to dist/src and build from dist/src into dist, so that # the source map for index.js.map will refer to ./src/index.ts etc cp -rp src README.md dist -rm dist/src/_shims/*-deno.ts dist/src/_shims/auto/*-deno.ts for file in LICENSE CHANGELOG.md; do if [ -e "${file}" ]; then cp "${file}" dist; fi done @@ -29,9 +28,6 @@ node scripts/utils/make-dist-package-json.cjs > dist/package.json # build to .js/.mjs/.d.ts files npm exec tsc-multi -# copy over handwritten .js/.mjs/.d.ts files -cp src/_shims/*.{d.ts,js,mjs,md} dist/_shims -cp src/_shims/auto/*.{d.ts,js,mjs} dist/_shims/auto # we need to add exports = module.exports = OpenAI to index.js; # No way to get that from index.ts because it would cause compile errors # when building .mjs @@ -42,6 +38,10 @@ node scripts/utils/fix-index-exports.cjs # the same export default statement) cp dist/index.d.ts dist/index.d.mts cp tsconfig.dist-src.json dist/src/tsconfig.json +cp src/internal/shim-types.d.ts dist/internal/shim-types.d.ts +cp src/internal/shim-types.d.ts dist/internal/shim-types.d.mts +mkdir -p dist/internal/shims +cp src/internal/shims/*.{mjs,js,d.ts} dist/internal/shims node scripts/utils/postprocess-files.cjs diff --git a/scripts/build-deno b/scripts/build-deno index bce31078e..028d9dfe5 100755 --- a/scripts/build-deno +++ b/scripts/build-deno @@ -7,21 +7,6 @@ cd "$(dirname "$0")/.." rm -rf dist-deno; mkdir dist-deno cp -rp src/* jsr.json dist-deno -rm -rf dist-deno/shims - -rm dist-deno/_shims/node*.{js,mjs,ts} -rm dist-deno/_shims/manual*.{js,mjs,ts} -rm dist-deno/_shims/index.{d.ts,js,mjs} -for file in dist-deno/_shims/*-deno.ts; do - mv -- "$file" "${file%-deno.ts}.ts" -done - -rm dist-deno/_shims/auto/*-node.ts -rm dist-deno/_shims/auto/*.{d.ts,js,mjs} -for file in dist-deno/_shims/auto/*-deno.ts; do - mv -- "$file" "${file%-deno.ts}.ts" -done - for file in README.md LICENSE CHANGELOG.md; do if [ -e "${file}" ]; then cp "${file}" dist-deno; fi done diff --git a/scripts/format b/scripts/format index a6bb9d03a..903b1ef85 100755 --- a/scripts/format +++ b/scripts/format @@ -5,4 +5,4 @@ set -e cd "$(dirname "$0")/.." echo "==> Running eslint --fix" -ESLINT_USE_FLAT_CONFIG="false" ./node_modules/.bin/eslint --fix --ext ts,js . +./node_modules/.bin/eslint --fix . diff --git a/scripts/lint b/scripts/lint index 6ba75dfb5..3ffb78a64 100755 --- a/scripts/lint +++ b/scripts/lint @@ -5,7 +5,17 @@ set -e cd "$(dirname "$0")/.." echo "==> Running eslint" -ESLINT_USE_FLAT_CONFIG="false" ./node_modules/.bin/eslint --ext ts,js . +./node_modules/.bin/eslint . -echo "==> Running tsc" -./node_modules/.bin/tsc --noEmit +echo "==> Building" +./scripts/build + +echo "==> Checking types" +./node_modules/typescript/bin/tsc + +echo "==> Running Are The Types Wrong?" +./node_modules/.bin/attw --pack dist -f json >.attw.json || true +node scripts/utils/attw-report.cjs + +echo "==> Running publint" +./node_modules/.bin/publint dist diff --git a/scripts/utils/attw-report.cjs b/scripts/utils/attw-report.cjs new file mode 100644 index 000000000..b3477c0ef --- /dev/null +++ b/scripts/utils/attw-report.cjs @@ -0,0 +1,24 @@ +const fs = require('fs'); +const problems = Object.values(JSON.parse(fs.readFileSync('.attw.json', 'utf-8')).problems) + .flat() + .filter( + (problem) => + !( + // This is intentional, if the user specifies .mjs they get ESM. + ( + (problem.kind === 'CJSResolvesToESM' && problem.entrypoint.endsWith('.mjs')) || + // This is intentional for backwards compat reasons. + (problem.kind === 'MissingExportEquals' && problem.implementationFileName.endsWith('/index.js')) || + // this is intentional, we deliberately attempt to import types that may not exist from parent node_modules + // folders to better support various runtimes without triggering automatic type acquisition. + (problem.kind === 'InternalResolutionError' && problem.moduleSpecifier.includes('node_modules')) + ) + ), + ); +fs.unlinkSync('.attw.json'); +if (problems.length) { + process.stdout.write('The types are wrong!\n' + JSON.stringify(problems, null, 2) + '\n'); + process.exitCode = 1; +} else { + process.stdout.write('Types ok!\n'); +} diff --git a/scripts/utils/fix-index-exports.cjs b/scripts/utils/fix-index-exports.cjs index ee5cebb85..e5e10b3e7 100644 --- a/scripts/utils/fix-index-exports.cjs +++ b/scripts/utils/fix-index-exports.cjs @@ -8,7 +8,10 @@ const indexJs = let before = fs.readFileSync(indexJs, 'utf8'); let after = before.replace( - /^\s*exports\.default\s*=\s*(\w+)/m, - 'exports = module.exports = $1;\nmodule.exports.AzureOpenAI = AzureOpenAI;\nexports.default = $1', + /^(\s*Object\.defineProperty\s*\(exports,\s*["']__esModule["'].+)$/m, + `exports = module.exports = function (...args) { + return new exports.default(...args) + } + $1`.replace(/^ /gm, ''), ); fs.writeFileSync(indexJs, after, 'utf8'); diff --git a/scripts/utils/postprocess-files.cjs b/scripts/utils/postprocess-files.cjs index c46a46d07..d16c8641c 100644 --- a/scripts/utils/postprocess-files.cjs +++ b/scripts/utils/postprocess-files.cjs @@ -1,98 +1,11 @@ +// @ts-check const fs = require('fs'); const path = require('path'); -const { parse } = require('@typescript-eslint/parser'); - -const pkgImportPath = process.env['PKG_IMPORT_PATH'] ?? 'openai/'; const distDir = process.env['DIST_PATH'] ? path.resolve(process.env['DIST_PATH']) : path.resolve(__dirname, '..', '..', 'dist'); -const distSrcDir = path.join(distDir, 'src'); - -/** - * Quick and dirty AST traversal - */ -function traverse(node, visitor) { - if (!node || typeof node.type !== 'string') return; - visitor.node?.(node); - visitor[node.type]?.(node); - for (const key in node) { - const value = node[key]; - if (Array.isArray(value)) { - for (const elem of value) traverse(elem, visitor); - } else if (value instanceof Object) { - traverse(value, visitor); - } - } -} - -/** - * Helper method for replacing arbitrary ranges of text in input code. - * - * The `replacer` is a function that will be called with a mini-api. For example: - * - * replaceRanges('foobar', ({ replace }) => replace([0, 3], 'baz')) // 'bazbar' - * - * The replaced ranges must not be overlapping. - */ -function replaceRanges(code, replacer) { - const replacements = []; - replacer({ replace: (range, replacement) => replacements.push({ range, replacement }) }); - - if (!replacements.length) return code; - replacements.sort((a, b) => a.range[0] - b.range[0]); - const overlapIndex = replacements.findIndex( - (r, index) => index > 0 && replacements[index - 1].range[1] > r.range[0], - ); - if (overlapIndex >= 0) { - throw new Error( - `replacements overlap: ${JSON.stringify(replacements[overlapIndex - 1])} and ${JSON.stringify( - replacements[overlapIndex], - )}`, - ); - } - - const parts = []; - let end = 0; - for (const { - range: [from, to], - replacement, - } of replacements) { - if (from > end) parts.push(code.substring(end, from)); - parts.push(replacement); - end = to; - } - if (end < code.length) parts.push(code.substring(end)); - return parts.join(''); -} - -/** - * Like calling .map(), where the iteratee is called on the path in every import or export from statement. - * @returns the transformed code - */ -function mapModulePaths(code, iteratee) { - const ast = parse(code, { range: true }); - return replaceRanges(code, ({ replace }) => - traverse(ast, { - node(node) { - switch (node.type) { - case 'ImportDeclaration': - case 'ExportNamedDeclaration': - case 'ExportAllDeclaration': - case 'ImportExpression': - if (node.source) { - const { range, value } = node.source; - const transformed = iteratee(value); - if (transformed !== value) { - replace(range, JSON.stringify(transformed)); - } - } - } - }, - }), - ); -} async function* walk(dir) { for await (const d of await fs.promises.opendir(dir)) { @@ -103,63 +16,79 @@ async function* walk(dir) { } async function postprocess() { - for await (const file of walk(path.resolve(__dirname, '..', '..', 'dist'))) { - if (!/\.([cm]?js|(\.d)?[cm]?ts)$/.test(file)) continue; + for await (const file of walk(distDir)) { + if (!/(\.d)?[cm]?ts$/.test(file)) continue; const code = await fs.promises.readFile(file, 'utf8'); - let transformed = mapModulePaths(code, (importPath) => { - if (file.startsWith(distSrcDir)) { - if (importPath.startsWith(pkgImportPath)) { - // convert self-references in dist/src to relative paths - let relativePath = path.relative( - path.dirname(file), - path.join(distSrcDir, importPath.substring(pkgImportPath.length)), - ); - if (!relativePath.startsWith('.')) relativePath = `./${relativePath}`; - return relativePath; - } - return importPath; - } - if (importPath.startsWith('.')) { - // add explicit file extensions to relative imports - const { dir, name } = path.parse(importPath); - const ext = /\.mjs$/.test(file) ? '.mjs' : '.js'; - return `${dir}/${name}${ext}`; - } - return importPath; - }); - - if (file.startsWith(distSrcDir) && !file.endsWith('_shims/index.d.ts')) { - // strip out `unknown extends Foo ? never :` shim guards in dist/src - // to prevent errors from appearing in Go To Source - transformed = transformed.replace( - new RegExp('unknown extends (typeof )?\\S+ \\? \\S+ :\\s*'.replace(/\s+/, '\\s+'), 'gm'), - // replace with same number of characters to avoid breaking source maps - (match) => ' '.repeat(match.length), - ); - } - - if (file.endsWith('.d.ts')) { - // work around bad tsc behavior - // if we have `import { type Readable } from 'openai/_shims/index'`, - // tsc sometimes replaces `Readable` with `import("stream").Readable` inline - // in the output .d.ts - transformed = transformed.replace(/import\("stream"\).Readable/g, 'Readable'); - } - - // strip out lib="dom" and types="node" references; these are needed at build time, - // but would pollute the user's TS environment - transformed = transformed.replace( - /^ *\/\/\/ * ' '.repeat(match.length - 1) + '\n', ); if (transformed !== code) { - await fs.promises.writeFile(file, transformed, 'utf8'); console.error(`wrote ${path.relative(process.cwd(), file)}`); + await fs.promises.writeFile(file, transformed, 'utf8'); + } + } + + const newExports = { + '.': { + require: { + types: './index.d.ts', + default: './index.js', + }, + types: './index.d.mts', + default: './index.mjs', + }, + }; + + for (const entry of await fs.promises.readdir(distDir, { withFileTypes: true })) { + if (entry.isDirectory() && entry.name !== 'src' && entry.name !== 'internal' && entry.name !== 'bin') { + const subpath = './' + entry.name; + newExports[subpath + '/*.mjs'] = { + default: [subpath + '/*.mjs', subpath + '/*/index.mjs'], + }; + newExports[subpath + '/*.js'] = { + default: [subpath + '/*.js', subpath + '/*/index.js'], + }; + newExports[subpath + '/*'] = { + import: [subpath + '/*.mjs', subpath + '/*/index.mjs'], + require: [subpath + '/*.js', subpath + '/*/index.js'], + }; + } else if (entry.isFile() && /\.[cm]?js$/.test(entry.name)) { + const { name, ext } = path.parse(entry.name); + const subpathWithoutExt = './' + name; + const subpath = './' + entry.name; + newExports[subpathWithoutExt] ||= { import: undefined, require: undefined }; + const isModule = ext[1] === 'm'; + if (isModule) { + newExports[subpathWithoutExt].import = subpath; + } else { + newExports[subpathWithoutExt].require = subpath; + } + newExports[subpath] = { + default: subpath, + }; } } + await fs.promises.writeFile( + 'dist/package.json', + JSON.stringify( + Object.assign( + /** @type {Record} */ ( + JSON.parse(await fs.promises.readFile('dist/package.json', 'utf-8')) + ), + { + exports: newExports, + }, + ), + null, + 2, + ), + ); } postprocess(); diff --git a/src/_shims/MultipartBody.ts b/src/_shims/MultipartBody.ts deleted file mode 100644 index af3b11188..000000000 --- a/src/_shims/MultipartBody.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Disclaimer: modules in _shims aren't intended to be imported by SDK users. - */ -export class MultipartBody { - constructor(public body: any) {} - get [Symbol.toStringTag](): string { - return 'MultipartBody'; - } -} diff --git a/src/_shims/README.md b/src/_shims/README.md deleted file mode 100644 index b3a349b41..000000000 --- a/src/_shims/README.md +++ /dev/null @@ -1,46 +0,0 @@ -# 👋 Wondering what everything in here does? - -`openai` supports a wide variety of runtime environments like Node.js, Deno, Bun, browsers, and various -edge runtimes, as well as both CommonJS (CJS) and EcmaScript Modules (ESM). - -To do this, `openai` provides shims for either using `node-fetch` when in Node (because `fetch` is still experimental there) or the global `fetch` API built into the environment when not in Node. - -It uses [conditional exports](https://nodejs.org/api/packages.html#conditional-exports) to -automatically select the correct shims for each environment. However, conditional exports are a fairly new -feature and not supported everywhere. For instance, the TypeScript `"moduleResolution": "node"` - -setting doesn't consult the `exports` map, compared to `"moduleResolution": "nodeNext"`, which does. -Unfortunately that's still the default setting, and it can result in errors like -getting the wrong raw `Response` type from `.asResponse()`, for example. - -The user can work around these issues by manually importing one of: - -- `import 'openai/shims/node'` -- `import 'openai/shims/web'` - -All of the code here in `_shims` handles selecting the automatic default shims or manual overrides. - -### How it works - Runtime - -Runtime shims get installed by calling `setShims` exported by `openai/_shims/registry`. - -Manually importing `openai/shims/node` or `openai/shims/web`, calls `setShims` with the respective runtime shims. - -All client code imports shims from `openai/_shims/index`, which: - -- checks if shims have been set manually -- if not, calls `setShims` with the shims from `openai/_shims/auto/runtime` -- re-exports the installed shims from `openai/_shims/registry`. - -`openai/_shims/auto/runtime` exports web runtime shims. -If the `node` export condition is set, the export map replaces it with `openai/_shims/auto/runtime-node`. - -### How it works - Type time - -All client code imports shim types from `openai/_shims/index`, which selects the manual types from `openai/_shims/manual-types` if they have been declared, otherwise it exports the auto types from `openai/_shims/auto/types`. - -`openai/_shims/manual-types` exports an empty namespace. -Manually importing `openai/shims/node` or `openai/shims/web` merges declarations into this empty namespace, so they get picked up by `openai/_shims/index`. - -`openai/_shims/auto/types` exports web type definitions. -If the `node` export condition is set, the export map replaces it with `openai/_shims/auto/types-node`, though TS only picks this up if `"moduleResolution": "nodenext"` or `"moduleResolution": "bundler"`. diff --git a/src/_shims/auto/runtime-bun.ts b/src/_shims/auto/runtime-bun.ts deleted file mode 100644 index e053254b3..000000000 --- a/src/_shims/auto/runtime-bun.ts +++ /dev/null @@ -1,4 +0,0 @@ -/** - * Disclaimer: modules in _shims aren't intended to be imported by SDK users. - */ -export * from '../bun-runtime'; diff --git a/src/_shims/auto/runtime-deno.ts b/src/_shims/auto/runtime-deno.ts deleted file mode 100644 index 62b7a39ee..000000000 --- a/src/_shims/auto/runtime-deno.ts +++ /dev/null @@ -1,4 +0,0 @@ -/** - * Disclaimer: modules in _shims aren't intended to be imported by SDK users. - */ -export * from '../web-runtime'; diff --git a/src/_shims/auto/runtime-node.ts b/src/_shims/auto/runtime-node.ts deleted file mode 100644 index 0ae2216fe..000000000 --- a/src/_shims/auto/runtime-node.ts +++ /dev/null @@ -1,4 +0,0 @@ -/** - * Disclaimer: modules in _shims aren't intended to be imported by SDK users. - */ -export * from '../node-runtime'; diff --git a/src/_shims/auto/runtime.ts b/src/_shims/auto/runtime.ts deleted file mode 100644 index 62b7a39ee..000000000 --- a/src/_shims/auto/runtime.ts +++ /dev/null @@ -1,4 +0,0 @@ -/** - * Disclaimer: modules in _shims aren't intended to be imported by SDK users. - */ -export * from '../web-runtime'; diff --git a/src/_shims/auto/types-deno.ts b/src/_shims/auto/types-deno.ts deleted file mode 100644 index 226fb15a0..000000000 --- a/src/_shims/auto/types-deno.ts +++ /dev/null @@ -1,4 +0,0 @@ -/** - * Disclaimer: modules in _shims aren't intended to be imported by SDK users. - */ -export * from '../web-types'; diff --git a/src/_shims/auto/types-node.ts b/src/_shims/auto/types-node.ts deleted file mode 100644 index 2625a8b70..000000000 --- a/src/_shims/auto/types-node.ts +++ /dev/null @@ -1,4 +0,0 @@ -/** - * Disclaimer: modules in _shims aren't intended to be imported by SDK users. - */ -export * from '../node-types'; diff --git a/src/_shims/auto/types.d.ts b/src/_shims/auto/types.d.ts deleted file mode 100644 index d7755070b..000000000 --- a/src/_shims/auto/types.d.ts +++ /dev/null @@ -1,101 +0,0 @@ -/** - * Disclaimer: modules in _shims aren't intended to be imported by SDK users. - */ -export type Agent = any; - -// @ts-ignore -declare const _fetch: unknown extends typeof fetch ? never : typeof fetch; -export { _fetch as fetch }; - -// @ts-ignore -type _Request = unknown extends Request ? never : Request; -export { _Request as Request }; - -// @ts-ignore -type _RequestInfo = unknown extends RequestInfo ? never : RequestInfo; -export { type _RequestInfo as RequestInfo }; - -// @ts-ignore -type _RequestInit = unknown extends RequestInit ? never : RequestInit; -export { type _RequestInit as RequestInit }; - -// @ts-ignore -type _Response = unknown extends Response ? never : Response; -export { _Response as Response }; - -// @ts-ignore -type _ResponseInit = unknown extends ResponseInit ? never : ResponseInit; -export { type _ResponseInit as ResponseInit }; - -// @ts-ignore -type _ResponseType = unknown extends ResponseType ? never : ResponseType; -export { type _ResponseType as ResponseType }; - -// @ts-ignore -type _BodyInit = unknown extends BodyInit ? never : BodyInit; -export { type _BodyInit as BodyInit }; - -// @ts-ignore -type _Headers = unknown extends Headers ? never : Headers; -export { _Headers as Headers }; - -// @ts-ignore -type _HeadersInit = unknown extends HeadersInit ? never : HeadersInit; -export { type _HeadersInit as HeadersInit }; - -type EndingType = 'native' | 'transparent'; - -export interface BlobPropertyBag { - endings?: EndingType; - type?: string; -} - -export interface FilePropertyBag extends BlobPropertyBag { - lastModified?: number; -} - -export type FileFromPathOptions = Omit; - -// @ts-ignore -type _FormData = unknown extends FormData ? never : FormData; -// @ts-ignore -declare const _FormData: unknown extends typeof FormData ? never : typeof FormData; -export { _FormData as FormData }; - -// @ts-ignore -type _File = unknown extends File ? never : File; -// @ts-ignore -declare const _File: unknown extends typeof File ? never : typeof File; -export { _File as File }; - -// @ts-ignore -type _Blob = unknown extends Blob ? never : Blob; -// @ts-ignore -declare const _Blob: unknown extends typeof Blob ? never : typeof Blob; -export { _Blob as Blob }; - -export declare class Readable { - readable: boolean; - readonly readableEnded: boolean; - readonly readableFlowing: boolean | null; - readonly readableHighWaterMark: number; - readonly readableLength: number; - readonly readableObjectMode: boolean; - destroyed: boolean; - read(size?: number): any; - pause(): this; - resume(): this; - isPaused(): boolean; - destroy(error?: Error): this; - [Symbol.asyncIterator](): AsyncIterableIterator; -} - -export declare class FsReadStream extends Readable { - path: {}; // node type is string | Buffer -} - -// @ts-ignore -type _ReadableStream = unknown extends ReadableStream ? never : ReadableStream; -// @ts-ignore -declare const _ReadableStream: unknown extends typeof ReadableStream ? never : typeof ReadableStream; -export { _ReadableStream as ReadableStream }; diff --git a/src/_shims/auto/types.js b/src/_shims/auto/types.js deleted file mode 100644 index ddbdb799c..000000000 --- a/src/_shims/auto/types.js +++ /dev/null @@ -1,3 +0,0 @@ -/** - * Disclaimer: modules in _shims aren't intended to be imported by SDK users. - */ diff --git a/src/_shims/auto/types.mjs b/src/_shims/auto/types.mjs deleted file mode 100644 index ddbdb799c..000000000 --- a/src/_shims/auto/types.mjs +++ /dev/null @@ -1,3 +0,0 @@ -/** - * Disclaimer: modules in _shims aren't intended to be imported by SDK users. - */ diff --git a/src/_shims/bun-runtime.ts b/src/_shims/bun-runtime.ts deleted file mode 100644 index 8d5aaab0c..000000000 --- a/src/_shims/bun-runtime.ts +++ /dev/null @@ -1,14 +0,0 @@ -/** - * Disclaimer: modules in _shims aren't intended to be imported by SDK users. - */ -import { type Shims } from './registry'; -import { getRuntime as getWebRuntime } from './web-runtime'; -import { ReadStream as FsReadStream } from 'node:fs'; - -export function getRuntime(): Shims { - const runtime = getWebRuntime(); - function isFsReadStream(value: any): value is FsReadStream { - return value instanceof FsReadStream; - } - return { ...runtime, isFsReadStream }; -} diff --git a/src/_shims/index-deno.ts b/src/_shims/index-deno.ts deleted file mode 100644 index d9eabb5a9..000000000 --- a/src/_shims/index-deno.ts +++ /dev/null @@ -1,110 +0,0 @@ -import { MultipartBody } from './MultipartBody'; -import { type RequestOptions } from '../core'; - -export const kind: string = 'web'; - -export type Agent = any; - -const _fetch = fetch; -type _fetch = typeof fetch; -export { _fetch as fetch }; - -const _Request = Request; -type _Request = Request; -export { _Request as Request }; - -type _RequestInfo = RequestInfo; -export { type _RequestInfo as RequestInfo }; - -type _RequestInit = RequestInit; -export { type _RequestInit as RequestInit }; - -const _Response = Response; -type _Response = Response; -export { _Response as Response }; - -type _ResponseInit = ResponseInit; -export { type _ResponseInit as ResponseInit }; - -type _ResponseType = ResponseType; -export { type _ResponseType as ResponseType }; - -type _BodyInit = BodyInit; -export { type _BodyInit as BodyInit }; - -const _Headers = Headers; -type _Headers = Headers; -export { _Headers as Headers }; - -type _HeadersInit = HeadersInit; -export { type _HeadersInit as HeadersInit }; - -type EndingType = 'native' | 'transparent'; - -export interface BlobPropertyBag { - endings?: EndingType; - type?: string; -} - -export interface FilePropertyBag extends BlobPropertyBag { - lastModified?: number; -} - -export type FileFromPathOptions = Omit; - -const _FormData = FormData; -type _FormData = FormData; -export { _FormData as FormData }; - -const _File = File; -type _File = File; -export { _File as File }; - -const _Blob = Blob; -type _Blob = Blob; -export { _Blob as Blob }; - -export async function getMultipartRequestOptions>( - form: FormData, - opts: RequestOptions, -): Promise> { - return { - ...opts, - body: new MultipartBody(form) as any, - }; -} - -export function getDefaultAgent(url: string) { - return undefined; -} -export function fileFromPath() { - throw new Error( - 'The `fileFromPath` function is only supported in Node. See the README for more details: https://www.github.com/openai/openai-node#file-uploads', - ); -} - -export const isFsReadStream = (value: any) => false; - -export declare class Readable { - readable: boolean; - readonly readableEnded: boolean; - readonly readableFlowing: boolean | null; - readonly readableHighWaterMark: number; - readonly readableLength: number; - readonly readableObjectMode: boolean; - destroyed: boolean; - read(size?: number): any; - pause(): this; - resume(): this; - isPaused(): boolean; - destroy(error?: Error): this; - [Symbol.asyncIterator](): AsyncIterableIterator; -} - -export declare class FsReadStream extends Readable { - path: {}; // node type is string | Buffer -} - -const _ReadableStream = ReadableStream; -type _ReadableStream = ReadableStream; -export { _ReadableStream as ReadableStream }; diff --git a/src/_shims/index.d.ts b/src/_shims/index.d.ts deleted file mode 100644 index d867b293b..000000000 --- a/src/_shims/index.d.ts +++ /dev/null @@ -1,81 +0,0 @@ -/** - * Disclaimer: modules in _shims aren't intended to be imported by SDK users. - */ -import { manual } from './manual-types'; -import * as auto from 'openai/_shims/auto/types'; -import { type RequestOptions } from '../core'; - -type SelectType = unknown extends Manual ? Auto : Manual; - -export const kind: string; - -// @ts-ignore -export type Agent = SelectType; - -// @ts-ignore -export const fetch: SelectType; - -// @ts-ignore -export type Request = SelectType; -// @ts-ignore -export type RequestInfo = SelectType; -// @ts-ignore -export type RequestInit = SelectType; - -// @ts-ignore -export type Response = SelectType; -// @ts-ignore -export type ResponseInit = SelectType; -// @ts-ignore -export type ResponseType = SelectType; -// @ts-ignore -export type BodyInit = SelectType; -// @ts-ignore -export type Headers = SelectType; -// @ts-ignore -export const Headers: SelectType; -// @ts-ignore -export type HeadersInit = SelectType; - -// @ts-ignore -export type BlobPropertyBag = SelectType; -// @ts-ignore -export type FilePropertyBag = SelectType; -// @ts-ignore -export type FileFromPathOptions = SelectType; -// @ts-ignore -export type FormData = SelectType; -// @ts-ignore -export const FormData: SelectType; -// @ts-ignore -export type File = SelectType; -// @ts-ignore -export const File: SelectType; -// @ts-ignore -export type Blob = SelectType; -// @ts-ignore -export const Blob: SelectType; - -// @ts-ignore -export type Readable = SelectType; -// @ts-ignore -export type FsReadStream = SelectType; -// @ts-ignore -export type ReadableStream = SelectType; -// @ts-ignore -export const ReadableStream: SelectType; - -export function getMultipartRequestOptions>( - form: FormData, - opts: RequestOptions, -): Promise>; - -export function getDefaultAgent(url: string): any; - -// @ts-ignore -export type FileFromPathOptions = SelectType; - -export function fileFromPath(path: string, options?: FileFromPathOptions): Promise; -export function fileFromPath(path: string, filename?: string, options?: FileFromPathOptions): Promise; - -export function isFsReadStream(value: any): value is FsReadStream; diff --git a/src/_shims/index.js b/src/_shims/index.js deleted file mode 100644 index b5fc8229e..000000000 --- a/src/_shims/index.js +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Disclaimer: modules in _shims aren't intended to be imported by SDK users. - */ -const shims = require('./registry'); -const auto = require('openai/_shims/auto/runtime'); -if (!shims.kind) shims.setShims(auto.getRuntime(), { auto: true }); -for (const property of Object.keys(shims)) { - Object.defineProperty(exports, property, { - get() { - return shims[property]; - }, - }); -} diff --git a/src/_shims/index.mjs b/src/_shims/index.mjs deleted file mode 100644 index 81665e610..000000000 --- a/src/_shims/index.mjs +++ /dev/null @@ -1,7 +0,0 @@ -/** - * Disclaimer: modules in _shims aren't intended to be imported by SDK users. - */ -import * as shims from './registry.mjs'; -import * as auto from 'openai/_shims/auto/runtime'; -if (!shims.kind) shims.setShims(auto.getRuntime(), { auto: true }); -export * from './registry.mjs'; diff --git a/src/_shims/manual-types.d.ts b/src/_shims/manual-types.d.ts deleted file mode 100644 index 3d00fc243..000000000 --- a/src/_shims/manual-types.d.ts +++ /dev/null @@ -1,12 +0,0 @@ -/** - * Disclaimer: modules in _shims aren't intended to be imported by SDK users. - */ -/** - * Types will get added to this namespace when you import one of the following: - * - * import 'openai/shims/node' - * import 'openai/shims/web' - * - * Importing more than one will cause type and runtime errors. - */ -export namespace manual {} diff --git a/src/_shims/manual-types.js b/src/_shims/manual-types.js deleted file mode 100644 index ddbdb799c..000000000 --- a/src/_shims/manual-types.js +++ /dev/null @@ -1,3 +0,0 @@ -/** - * Disclaimer: modules in _shims aren't intended to be imported by SDK users. - */ diff --git a/src/_shims/manual-types.mjs b/src/_shims/manual-types.mjs deleted file mode 100644 index ddbdb799c..000000000 --- a/src/_shims/manual-types.mjs +++ /dev/null @@ -1,3 +0,0 @@ -/** - * Disclaimer: modules in _shims aren't intended to be imported by SDK users. - */ diff --git a/src/_shims/node-runtime.ts b/src/_shims/node-runtime.ts deleted file mode 100644 index ab9f2ab5c..000000000 --- a/src/_shims/node-runtime.ts +++ /dev/null @@ -1,81 +0,0 @@ -/** - * Disclaimer: modules in _shims aren't intended to be imported by SDK users. - */ -import * as nf from 'node-fetch'; -import * as fd from 'formdata-node'; -import { type File, type FilePropertyBag } from 'formdata-node'; -import KeepAliveAgent from 'agentkeepalive'; -import { AbortController as AbortControllerPolyfill } from 'abort-controller'; -import { ReadStream as FsReadStream } from 'node:fs'; -import { type Agent } from 'node:http'; -import { FormDataEncoder } from 'form-data-encoder'; -import { Readable } from 'node:stream'; -import { type RequestOptions } from '../core'; -import { MultipartBody } from './MultipartBody'; -import { type Shims } from './registry'; -import { ReadableStream } from 'node:stream/web'; - -type FileFromPathOptions = Omit; - -let fileFromPathWarned = false; - -/** - * @deprecated use fs.createReadStream('./my/file.txt') instead - */ -async function fileFromPath(path: string): Promise; -async function fileFromPath(path: string, filename?: string): Promise; -async function fileFromPath(path: string, options?: FileFromPathOptions): Promise; -async function fileFromPath(path: string, filename?: string, options?: FileFromPathOptions): Promise; -async function fileFromPath(path: string, ...args: any[]): Promise { - // this import fails in environments that don't handle export maps correctly, like old versions of Jest - const { fileFromPath: _fileFromPath } = await import('formdata-node/file-from-path'); - - if (!fileFromPathWarned) { - console.warn(`fileFromPath is deprecated; use fs.createReadStream(${JSON.stringify(path)}) instead`); - fileFromPathWarned = true; - } - // @ts-ignore - return await _fileFromPath(path, ...args); -} - -const defaultHttpAgent: Agent = new KeepAliveAgent({ keepAlive: true, timeout: 5 * 60 * 1000 }); -const defaultHttpsAgent: Agent = new KeepAliveAgent.HttpsAgent({ keepAlive: true, timeout: 5 * 60 * 1000 }); - -async function getMultipartRequestOptions>( - form: fd.FormData, - opts: RequestOptions, -): Promise> { - const encoder = new FormDataEncoder(form); - const readable = Readable.from(encoder); - const body = new MultipartBody(readable); - const headers = { - ...opts.headers, - ...encoder.headers, - 'Content-Length': encoder.contentLength, - }; - - return { ...opts, body: body as any, headers }; -} - -export function getRuntime(): Shims { - // Polyfill global object if needed. - if (typeof AbortController === 'undefined') { - // @ts-expect-error (the types are subtly different, but compatible in practice) - globalThis.AbortController = AbortControllerPolyfill; - } - return { - kind: 'node', - fetch: nf.default, - Request: nf.Request, - Response: nf.Response, - Headers: nf.Headers, - FormData: fd.FormData, - Blob: fd.Blob, - File: fd.File, - ReadableStream, - getMultipartRequestOptions, - getDefaultAgent: (url: string): Agent => (url.startsWith('https') ? defaultHttpsAgent : defaultHttpAgent), - fileFromPath, - isFsReadStream: (value: any): value is FsReadStream => value instanceof FsReadStream, - }; -} diff --git a/src/_shims/node-types.d.ts b/src/_shims/node-types.d.ts deleted file mode 100644 index c159e5fa7..000000000 --- a/src/_shims/node-types.d.ts +++ /dev/null @@ -1,42 +0,0 @@ -/** - * Disclaimer: modules in _shims aren't intended to be imported by SDK users. - */ -import * as nf from 'node-fetch'; -import * as fd from 'formdata-node'; - -export { type Agent } from 'node:http'; -export { type Readable } from 'node:stream'; -export { type ReadStream as FsReadStream } from 'node:fs'; -export { ReadableStream } from 'node:stream/web'; - -export const fetch: typeof nf.default; - -export type Request = nf.Request; -export type RequestInfo = nf.RequestInfo; -export type RequestInit = nf.RequestInit; - -export type Response = nf.Response; -export type ResponseInit = nf.ResponseInit; -export type ResponseType = nf.ResponseType; -export type BodyInit = nf.BodyInit; -export type Headers = nf.Headers; -export type HeadersInit = nf.HeadersInit; - -type EndingType = 'native' | 'transparent'; -export interface BlobPropertyBag { - endings?: EndingType; - type?: string; -} - -export interface FilePropertyBag extends BlobPropertyBag { - lastModified?: number; -} - -export type FileFromPathOptions = Omit; - -export type FormData = fd.FormData; -export const FormData: typeof fd.FormData; -export type File = fd.File; -export const File: typeof fd.File; -export type Blob = fd.Blob; -export const Blob: typeof fd.Blob; diff --git a/src/_shims/node-types.js b/src/_shims/node-types.js deleted file mode 100644 index ddbdb799c..000000000 --- a/src/_shims/node-types.js +++ /dev/null @@ -1,3 +0,0 @@ -/** - * Disclaimer: modules in _shims aren't intended to be imported by SDK users. - */ diff --git a/src/_shims/node-types.mjs b/src/_shims/node-types.mjs deleted file mode 100644 index ddbdb799c..000000000 --- a/src/_shims/node-types.mjs +++ /dev/null @@ -1,3 +0,0 @@ -/** - * Disclaimer: modules in _shims aren't intended to be imported by SDK users. - */ diff --git a/src/_shims/registry.ts b/src/_shims/registry.ts deleted file mode 100644 index 1fa39642e..000000000 --- a/src/_shims/registry.ts +++ /dev/null @@ -1,65 +0,0 @@ -/** - * Disclaimer: modules in _shims aren't intended to be imported by SDK users. - */ -import { type RequestOptions } from '../core'; - -export interface Shims { - kind: string; - fetch: any; - Request: any; - Response: any; - Headers: any; - FormData: any; - Blob: any; - File: any; - ReadableStream: any; - getMultipartRequestOptions: >( - form: Shims['FormData'], - opts: RequestOptions, - ) => Promise>; - getDefaultAgent: (url: string) => any; - fileFromPath: - | ((path: string, filename?: string, options?: {}) => Promise) - | ((path: string, options?: {}) => Promise); - isFsReadStream: (value: any) => boolean; -} - -export let auto = false; -export let kind: Shims['kind'] | undefined = undefined; -export let fetch: Shims['fetch'] | undefined = undefined; -export let Request: Shims['Request'] | undefined = undefined; -export let Response: Shims['Response'] | undefined = undefined; -export let Headers: Shims['Headers'] | undefined = undefined; -export let FormData: Shims['FormData'] | undefined = undefined; -export let Blob: Shims['Blob'] | undefined = undefined; -export let File: Shims['File'] | undefined = undefined; -export let ReadableStream: Shims['ReadableStream'] | undefined = undefined; -export let getMultipartRequestOptions: Shims['getMultipartRequestOptions'] | undefined = undefined; -export let getDefaultAgent: Shims['getDefaultAgent'] | undefined = undefined; -export let fileFromPath: Shims['fileFromPath'] | undefined = undefined; -export let isFsReadStream: Shims['isFsReadStream'] | undefined = undefined; - -export function setShims(shims: Shims, options: { auto: boolean } = { auto: false }) { - if (auto) { - throw new Error( - `you must \`import 'openai/shims/${shims.kind}'\` before importing anything else from openai`, - ); - } - if (kind) { - throw new Error(`can't \`import 'openai/shims/${shims.kind}'\` after \`import 'openai/shims/${kind}'\``); - } - auto = options.auto; - kind = shims.kind; - fetch = shims.fetch; - Request = shims.Request; - Response = shims.Response; - Headers = shims.Headers; - FormData = shims.FormData; - Blob = shims.Blob; - File = shims.File; - ReadableStream = shims.ReadableStream; - getMultipartRequestOptions = shims.getMultipartRequestOptions; - getDefaultAgent = shims.getDefaultAgent; - fileFromPath = shims.fileFromPath; - isFsReadStream = shims.isFsReadStream; -} diff --git a/src/_shims/web-runtime.ts b/src/_shims/web-runtime.ts deleted file mode 100644 index a5e90bcf8..000000000 --- a/src/_shims/web-runtime.ts +++ /dev/null @@ -1,103 +0,0 @@ -/** - * Disclaimer: modules in _shims aren't intended to be imported by SDK users. - */ -import { MultipartBody } from './MultipartBody'; -import { type RequestOptions } from '../core'; -import { type Shims } from './registry'; - -export function getRuntime({ manuallyImported }: { manuallyImported?: boolean } = {}): Shims { - const recommendation = - manuallyImported ? - `You may need to use polyfills` - : `Add one of these imports before your first \`import … from 'openai'\`: -- \`import 'openai/shims/node'\` (if you're running on Node) -- \`import 'openai/shims/web'\` (otherwise) -`; - - let _fetch, _Request, _Response, _Headers; - try { - // @ts-ignore - _fetch = fetch; - // @ts-ignore - _Request = Request; - // @ts-ignore - _Response = Response; - // @ts-ignore - _Headers = Headers; - } catch (error) { - throw new Error( - `this environment is missing the following Web Fetch API type: ${ - (error as any).message - }. ${recommendation}`, - ); - } - - return { - kind: 'web', - fetch: _fetch, - Request: _Request, - Response: _Response, - Headers: _Headers, - FormData: - // @ts-ignore - typeof FormData !== 'undefined' ? FormData : ( - class FormData { - // @ts-ignore - constructor() { - throw new Error( - `file uploads aren't supported in this environment yet as 'FormData' is undefined. ${recommendation}`, - ); - } - } - ), - Blob: - typeof Blob !== 'undefined' ? Blob : ( - class Blob { - constructor() { - throw new Error( - `file uploads aren't supported in this environment yet as 'Blob' is undefined. ${recommendation}`, - ); - } - } - ), - File: - // @ts-ignore - typeof File !== 'undefined' ? File : ( - class File { - // @ts-ignore - constructor() { - throw new Error( - `file uploads aren't supported in this environment yet as 'File' is undefined. ${recommendation}`, - ); - } - } - ), - ReadableStream: - // @ts-ignore - typeof ReadableStream !== 'undefined' ? ReadableStream : ( - class ReadableStream { - // @ts-ignore - constructor() { - throw new Error( - `streaming isn't supported in this environment yet as 'ReadableStream' is undefined. ${recommendation}`, - ); - } - } - ), - getMultipartRequestOptions: async >( - // @ts-ignore - form: FormData, - opts: RequestOptions, - ): Promise> => ({ - ...opts, - body: new MultipartBody(form) as any, - }), - getDefaultAgent: (url: string) => undefined, - fileFromPath: () => { - throw new Error( - 'The `fileFromPath` function is only supported in Node. See the README for more details: https://www.github.com/openai/openai-node#file-uploads', - ); - }, - isFsReadStream: (value: any) => false, - }; -} diff --git a/src/_shims/web-types.d.ts b/src/_shims/web-types.d.ts deleted file mode 100644 index 4ff351383..000000000 --- a/src/_shims/web-types.d.ts +++ /dev/null @@ -1,83 +0,0 @@ -/** - * Disclaimer: modules in _shims aren't intended to be imported by SDK users. - */ -export type Agent = any; - -declare const _fetch: typeof fetch; -export { _fetch as fetch }; - -type _Request = Request; -export { _Request as Request }; - -type _RequestInfo = RequestInfo; -export { type _RequestInfo as RequestInfo }; - -type _RequestInit = RequestInit; -export { type _RequestInit as RequestInit }; - -type _Response = Response; -export { _Response as Response }; - -type _ResponseInit = ResponseInit; -export { type _ResponseInit as ResponseInit }; - -type _ResponseType = ResponseType; -export { type _ResponseType as ResponseType }; - -type _BodyInit = BodyInit; -export { type _BodyInit as BodyInit }; - -type _Headers = Headers; -export { _Headers as Headers }; - -type _HeadersInit = HeadersInit; -export { type _HeadersInit as HeadersInit }; - -type EndingType = 'native' | 'transparent'; - -export interface BlobPropertyBag { - endings?: EndingType; - type?: string; -} - -export interface FilePropertyBag extends BlobPropertyBag { - lastModified?: number; -} - -export type FileFromPathOptions = Omit; - -type _FormData = FormData; -declare const _FormData: typeof FormData; -export { _FormData as FormData }; - -type _File = File; -declare const _File: typeof File; -export { _File as File }; - -type _Blob = Blob; -declare const _Blob: typeof Blob; -export { _Blob as Blob }; - -export declare class Readable { - readable: boolean; - readonly readableEnded: boolean; - readonly readableFlowing: boolean | null; - readonly readableHighWaterMark: number; - readonly readableLength: number; - readonly readableObjectMode: boolean; - destroyed: boolean; - read(size?: number): any; - pause(): this; - resume(): this; - isPaused(): boolean; - destroy(error?: Error): this; - [Symbol.asyncIterator](): AsyncIterableIterator; -} - -export declare class FsReadStream extends Readable { - path: {}; // node type is string | Buffer -} - -type _ReadableStream = ReadableStream; -declare const _ReadableStream: typeof ReadableStream; -export { _ReadableStream as ReadableStream }; diff --git a/src/_shims/web-types.js b/src/_shims/web-types.js deleted file mode 100644 index ddbdb799c..000000000 --- a/src/_shims/web-types.js +++ /dev/null @@ -1,3 +0,0 @@ -/** - * Disclaimer: modules in _shims aren't intended to be imported by SDK users. - */ diff --git a/src/_shims/web-types.mjs b/src/_shims/web-types.mjs deleted file mode 100644 index ddbdb799c..000000000 --- a/src/_shims/web-types.mjs +++ /dev/null @@ -1,3 +0,0 @@ -/** - * Disclaimer: modules in _shims aren't intended to be imported by SDK users. - */ diff --git a/src/api-promise.ts b/src/api-promise.ts new file mode 100644 index 000000000..c9d9a9a9f --- /dev/null +++ b/src/api-promise.ts @@ -0,0 +1,101 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { type OpenAI } from './client'; + +import { type PromiseOrValue } from './internal/types'; +import { + type APIResponseProps, + defaultParseResponse, + type WithRequestID, + addRequestID, +} from './internal/parse'; + +/** + * A subclass of `Promise` providing additional helper methods + * for interacting with the SDK. + */ +export class APIPromise extends Promise> { + private parsedPromise: Promise> | undefined; + #client: OpenAI; + + constructor( + client: OpenAI, + private responsePromise: Promise, + private parseResponse: ( + client: OpenAI, + props: APIResponseProps, + ) => PromiseOrValue> = defaultParseResponse, + ) { + super((resolve) => { + // this is maybe a bit weird but this has to be a no-op to not implicitly + // parse the response body; instead .then, .catch, .finally are overridden + // to parse the response + resolve(null as any); + }); + this.#client = client; + } + + _thenUnwrap(transform: (data: T, props: APIResponseProps) => U): APIPromise { + return new APIPromise(this.#client, this.responsePromise, async (client, props) => + addRequestID(transform(await this.parseResponse(client, props), props), props.response), + ); + } + + /** + * Gets the raw `Response` instance instead of parsing the response + * data. + * + * If you want to parse the response body but still get the `Response` + * instance, you can use {@link withResponse()}. + * + * 👋 Getting the wrong TypeScript type for `Response`? + * Try setting `"moduleResolution": "NodeNext"` or add `"lib": ["DOM"]` + * to your `tsconfig.json`. + */ + asResponse(): Promise { + return this.responsePromise.then((p) => p.response); + } + + /** + * Gets the parsed response data, the raw `Response` instance and the ID of the request, + * returned via the X-Request-ID header which is useful for debugging requests and reporting + * issues to OpenAI. + * + * If you just want to get the raw `Response` instance without parsing it, + * you can use {@link asResponse()}. + * + * 👋 Getting the wrong TypeScript type for `Response`? + * Try setting `"moduleResolution": "NodeNext"` or add `"lib": ["DOM"]` + * to your `tsconfig.json`. + */ + async withResponse(): Promise<{ data: T; response: Response; request_id: string | null }> { + const [data, response] = await Promise.all([this.parse(), this.asResponse()]); + return { data, response, request_id: response.headers.get('x-request-id') }; + } + + private parse(): Promise> { + if (!this.parsedPromise) { + this.parsedPromise = this.responsePromise.then((data) => + this.parseResponse(this.#client, data), + ) as any as Promise>; + } + return this.parsedPromise; + } + + override then, TResult2 = never>( + onfulfilled?: ((value: WithRequestID) => TResult1 | PromiseLike) | undefined | null, + onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null, + ): Promise { + return this.parse().then(onfulfilled, onrejected); + } + + override catch( + onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null, + ): Promise | TResult> { + return this.parse().catch(onrejected); + } + + override finally(onfinally?: (() => void) | undefined | null): Promise> { + return this.parse().finally(onfinally); + } +} diff --git a/src/azure.ts b/src/azure.ts new file mode 100644 index 000000000..661f288af --- /dev/null +++ b/src/azure.ts @@ -0,0 +1,197 @@ +import type { RequestInit } from './internal/builtin-types'; +import * as Errors from './error'; +import { FinalRequestOptions } from './internal/request-options'; +import { isObj, readEnv } from './internal/utils'; +import { ClientOptions, OpenAI } from './client'; +import { buildHeaders } from './internal/headers'; + +/** API Client for interfacing with the Azure OpenAI API. */ +export interface AzureClientOptions extends ClientOptions { + /** + * Defaults to process.env['OPENAI_API_VERSION']. + */ + apiVersion?: string | undefined; + + /** + * Your Azure endpoint, including the resource, e.g. `https://example-resource.azure.openai.com/` + */ + endpoint?: string | undefined; + + /** + * A model deployment, if given, sets the base client URL to include `/deployments/{deployment}`. + * Note: this means you won't be able to use non-deployment endpoints. Not supported with Assistants APIs. + */ + deployment?: string | undefined; + + /** + * Defaults to process.env['AZURE_OPENAI_API_KEY']. + */ + apiKey?: string | undefined; + + /** + * A function that returns an access token for Microsoft Entra (formerly known as Azure Active Directory), + * which will be invoked on every request. + */ + azureADTokenProvider?: (() => Promise) | undefined; +} + +/** API Client for interfacing with the Azure OpenAI API. */ +export class AzureOpenAI extends OpenAI { + private _azureADTokenProvider: (() => Promise) | undefined; + deploymentName: string | undefined; + apiVersion: string = ''; + + /** + * API Client for interfacing with the Azure OpenAI API. + * + * @param {string | undefined} [opts.apiVersion=process.env['OPENAI_API_VERSION'] ?? undefined] + * @param {string | undefined} [opts.endpoint=process.env['AZURE_OPENAI_ENDPOINT'] ?? undefined] - Your Azure endpoint, including the resource, e.g. `https://example-resource.azure.openai.com/` + * @param {string | undefined} [opts.apiKey=process.env['AZURE_OPENAI_API_KEY'] ?? undefined] + * @param {string | undefined} opts.deployment - A model deployment, if given, sets the base client URL to include `/deployments/{deployment}`. + * @param {string | null | undefined} [opts.organization=process.env['OPENAI_ORG_ID'] ?? null] + * @param {string} [opts.baseURL=process.env['OPENAI_BASE_URL']] - Sets the base URL for the API, e.g. `https://example-resource.azure.openai.com/openai/`. + * @param {number} [opts.timeout=10 minutes] - The maximum amount of time (in milliseconds) the client will wait for a response before timing out. + * @param {number} [opts.httpAgent] - An HTTP agent used to manage HTTP(s) connections. + * @param {Fetch} [opts.fetch] - Specify a custom `fetch` function implementation. + * @param {number} [opts.maxRetries=2] - The maximum number of times the client will retry a request. + * @param {Headers} opts.defaultHeaders - Default headers to include with every request to the API. + * @param {DefaultQuery} opts.defaultQuery - Default query parameters to include with every request to the API. + * @param {boolean} [opts.dangerouslyAllowBrowser=false] - By default, client-side use of this library is not allowed, as it risks exposing your secret API credentials to attackers. + */ + constructor({ + baseURL = readEnv('OPENAI_BASE_URL'), + apiKey = readEnv('AZURE_OPENAI_API_KEY'), + apiVersion = readEnv('OPENAI_API_VERSION'), + endpoint, + deployment, + azureADTokenProvider, + dangerouslyAllowBrowser, + ...opts + }: AzureClientOptions = {}) { + if (!apiVersion) { + throw new Errors.OpenAIError( + "The OPENAI_API_VERSION environment variable is missing or empty; either provide it, or instantiate the AzureOpenAI client with an apiVersion option, like new AzureOpenAI({ apiVersion: 'My API Version' }).", + ); + } + + if (typeof azureADTokenProvider === 'function') { + dangerouslyAllowBrowser = true; + } + + if (!azureADTokenProvider && !apiKey) { + throw new Errors.OpenAIError( + 'Missing credentials. Please pass one of `apiKey` and `azureADTokenProvider`, or set the `AZURE_OPENAI_API_KEY` environment variable.', + ); + } + + if (azureADTokenProvider && apiKey) { + throw new Errors.OpenAIError( + 'The `apiKey` and `azureADTokenProvider` arguments are mutually exclusive; only one can be passed at a time.', + ); + } + + // define a sentinel value to avoid any typing issues + apiKey ??= API_KEY_SENTINEL; + + opts.defaultQuery = { ...opts.defaultQuery, 'api-version': apiVersion }; + + if (!baseURL) { + if (!endpoint) { + endpoint = process.env['AZURE_OPENAI_ENDPOINT']; + } + + if (!endpoint) { + throw new Errors.OpenAIError( + 'Must provide one of the `baseURL` or `endpoint` arguments, or the `AZURE_OPENAI_ENDPOINT` environment variable', + ); + } + + baseURL = `${endpoint}/openai`; + } else { + if (endpoint) { + throw new Errors.OpenAIError('baseURL and endpoint are mutually exclusive'); + } + } + + super({ + apiKey, + baseURL, + ...opts, + ...(dangerouslyAllowBrowser !== undefined ? { dangerouslyAllowBrowser } : {}), + }); + + this._azureADTokenProvider = azureADTokenProvider; + this.apiVersion = apiVersion; + this.deploymentName = deployment; + } + + override buildRequest( + options: FinalRequestOptions, + props: { retryCount?: number } = {}, + ): { req: RequestInit & { headers: Headers }; url: string; timeout: number } { + if (_deployments_endpoints.has(options.path) && options.method === 'post' && options.body !== undefined) { + if (!isObj(options.body)) { + throw new Error('Expected request body to be an object'); + } + const model = this.deploymentName || options.body['model'] || options.__metadata?.['model']; + if (model !== undefined && !this.baseURL.includes('/deployments')) { + options.path = `/deployments/${model}${options.path}`; + } + } + return super.buildRequest(options, props); + } + + async _getAzureADToken(): Promise { + if (typeof this._azureADTokenProvider === 'function') { + const token = await this._azureADTokenProvider(); + if (!token || typeof token !== 'string') { + throw new Errors.OpenAIError( + `Expected 'azureADTokenProvider' argument to return a string but it returned ${token}`, + ); + } + return token; + } + return undefined; + } + + protected override authHeaders(opts: FinalRequestOptions): Headers { + return new Headers(); + } + + protected override async prepareOptions(opts: FinalRequestOptions): Promise { + opts.headers = buildHeaders([opts.headers]); + + /** + * The user should provide a bearer token provider if they want + * to use Azure AD authentication. The user shouldn't set the + * Authorization header manually because the header is overwritten + * with the Azure AD token if a bearer token provider is provided. + */ + if (opts.headers.values.get('Authorization') || opts.headers.values.get('api-key')) { + return super.prepareOptions(opts); + } + + const token = await this._getAzureADToken(); + if (token) { + opts.headers.values.set('Authorization', `Bearer ${token}`); + } else if (this.apiKey !== API_KEY_SENTINEL) { + opts.headers.values.set('api-key', this.apiKey); + } else { + throw new Errors.OpenAIError('Unable to handle auth'); + } + return super.prepareOptions(opts); + } +} + +const _deployments_endpoints = new Set([ + '/completions', + '/chat/completions', + '/embeddings', + '/audio/transcriptions', + '/audio/translations', + '/audio/speech', + '/images/generations', + '/batches', +]); + +const API_KEY_SENTINEL = ''; diff --git a/src/beta/realtime/index.ts b/src/beta/realtime/index.ts new file mode 100644 index 000000000..75f0f3088 --- /dev/null +++ b/src/beta/realtime/index.ts @@ -0,0 +1 @@ +export { OpenAIRealtimeError } from './internal-base'; diff --git a/src/beta/realtime/internal-base.ts b/src/beta/realtime/internal-base.ts new file mode 100644 index 000000000..b704812ee --- /dev/null +++ b/src/beta/realtime/internal-base.ts @@ -0,0 +1,93 @@ +import { RealtimeClientEvent, RealtimeServerEvent, ErrorEvent } from '../../resources/beta/realtime/realtime'; +import { EventEmitter } from '../../lib/EventEmitter'; +import { OpenAIError } from '../../error'; +import OpenAI, { AzureOpenAI } from '../../index'; + +export class OpenAIRealtimeError extends OpenAIError { + /** + * The error data that the API sent back in an `error` event. + */ + error?: ErrorEvent.Error | undefined; + + /** + * The unique ID of the server event. + */ + event_id?: string | undefined; + + constructor(message: string, event: ErrorEvent | null) { + super(message); + + this.error = event?.error; + this.event_id = event?.event_id; + } +} + +type Simplify = { [KeyType in keyof T]: T[KeyType] } & {}; + +type RealtimeEvents = Simplify< + { + event: (event: RealtimeServerEvent) => void; + error: (error: OpenAIRealtimeError) => void; + } & { + [EventType in Exclude]: ( + event: Extract, + ) => unknown; + } +>; + +export abstract class OpenAIRealtimeEmitter extends EventEmitter { + /** + * Send an event to the API. + */ + abstract send(event: RealtimeClientEvent): void; + + /** + * Close the websocket connection. + */ + abstract close(props?: { code: number; reason: string }): void; + + protected _onError(event: null, message: string, cause: any): void; + protected _onError(event: ErrorEvent, message?: string | undefined): void; + protected _onError(event: ErrorEvent | null, message?: string | undefined, cause?: any): void { + message = + event?.error ? + `${event.error.message} code=${event.error.code} param=${event.error.param} type=${event.error.type} event_id=${event.error.event_id}` + : message ?? 'unknown error'; + + if (!this._hasListener('error')) { + const error = new OpenAIRealtimeError( + message + + `\n\nTo resolve these unhandled rejection errors you should bind an \`error\` callback, e.g. \`rt.on('error', (error) => ...)\` `, + event, + ); + // @ts-ignore + error.cause = cause; + Promise.reject(error); + return; + } + + const error = new OpenAIRealtimeError(message, event); + // @ts-ignore + error.cause = cause; + + this._emit('error', error); + } +} + +export function isAzure(client: Pick): client is AzureOpenAI { + return client instanceof AzureOpenAI; +} + +export function buildRealtimeURL(client: Pick, model: string): URL { + const path = '/realtime'; + const baseURL = client.baseURL; + const url = new URL(baseURL + (baseURL.endsWith('/') ? path.slice(1) : path)); + url.protocol = 'wss'; + if (isAzure(client)) { + url.searchParams.set('api-version', client.apiVersion); + url.searchParams.set('deployment', model); + } else { + url.searchParams.set('model', model); + } + return url; +} diff --git a/src/beta/realtime/websocket.ts b/src/beta/realtime/websocket.ts new file mode 100644 index 000000000..2bf0b75d5 --- /dev/null +++ b/src/beta/realtime/websocket.ts @@ -0,0 +1,143 @@ +import { AzureOpenAI, OpenAI } from '../../index'; +import { OpenAIError } from '../../error'; +import type { RealtimeClientEvent, RealtimeServerEvent } from '../../resources/beta/realtime/realtime'; +import { OpenAIRealtimeEmitter, buildRealtimeURL, isAzure } from './internal-base'; +import { isRunningInBrowser } from '../../internal/detect-platform'; + +interface MessageEvent { + data: string; +} + +type _WebSocket = + typeof globalThis extends ( + { + WebSocket: infer ws extends abstract new (...args: any) => any; + } + ) ? + // @ts-ignore + InstanceType + : any; + +export class OpenAIRealtimeWebSocket extends OpenAIRealtimeEmitter { + url: URL; + socket: _WebSocket; + + constructor( + props: { + model: string; + dangerouslyAllowBrowser?: boolean; + /** + * Callback to mutate the URL, needed for Azure. + * @internal + */ + onURL?: (url: URL) => void; + }, + client?: Pick, + ) { + super(); + + const dangerouslyAllowBrowser = + props.dangerouslyAllowBrowser ?? + (client as any)?._options?.dangerouslyAllowBrowser ?? + (client?.apiKey.startsWith('ek_') ? true : null); + + if (!dangerouslyAllowBrowser && isRunningInBrowser()) { + throw new OpenAIError( + "It looks like you're running in a browser-like environment.\n\nThis is disabled by default, as it risks exposing your secret API credentials to attackers.\n\nYou can avoid this error by creating an ephemeral session token:\nhttps://platform.openai.com/docs/api-reference/realtime-sessions\n", + ); + } + + client ??= new OpenAI({ dangerouslyAllowBrowser }); + + this.url = buildRealtimeURL(client, props.model); + props.onURL?.(this.url); + + // @ts-ignore + this.socket = new WebSocket(this.url.toString(), [ + 'realtime', + ...(isAzure(client) ? [] : [`openai-insecure-api-key.${client.apiKey}`]), + 'openai-beta.realtime-v1', + ]); + + this.socket.addEventListener('message', (websocketEvent: MessageEvent) => { + const event = (() => { + try { + return JSON.parse(websocketEvent.data.toString()) as RealtimeServerEvent; + } catch (err) { + this._onError(null, 'could not parse websocket event', err); + return null; + } + })(); + + if (event) { + this._emit('event', event); + + if (event.type === 'error') { + this._onError(event); + } else { + // @ts-expect-error TS isn't smart enough to get the relationship right here + this._emit(event.type, event); + } + } + }); + + this.socket.addEventListener('error', (event: any) => { + this._onError(null, event.message, null); + }); + + if (isAzure(client)) { + if (this.url.searchParams.get('Authorization') !== null) { + this.url.searchParams.set('Authorization', ''); + } else { + this.url.searchParams.set('api-key', ''); + } + } + } + + static async azure( + client: Pick, + options: { deploymentName?: string; dangerouslyAllowBrowser?: boolean } = {}, + ): Promise { + const token = await client._getAzureADToken(); + function onURL(url: URL) { + if (client.apiKey !== '') { + url.searchParams.set('api-key', client.apiKey); + } else { + if (token) { + url.searchParams.set('Authorization', `Bearer ${token}`); + } else { + throw new Error('AzureOpenAI is not instantiated correctly. No API key or token provided.'); + } + } + } + const deploymentName = options.deploymentName ?? client.deploymentName; + if (!deploymentName) { + throw new Error('No deployment name provided'); + } + const { dangerouslyAllowBrowser } = options; + return new OpenAIRealtimeWebSocket( + { + model: deploymentName, + onURL, + ...(dangerouslyAllowBrowser ? { dangerouslyAllowBrowser } : {}), + }, + client, + ); + } + + send(event: RealtimeClientEvent) { + try { + this.socket.send(JSON.stringify(event)); + } catch (err) { + this._onError(null, 'could not send data', err); + } + } + + close(props?: { code: number; reason: string }) { + try { + this.socket.close(props?.code ?? 1000, props?.reason ?? 'OK'); + } catch (err) { + this._onError(null, 'could not close the connection', err); + } + } +} diff --git a/src/beta/realtime/ws.ts b/src/beta/realtime/ws.ts new file mode 100644 index 000000000..3f51dfc4b --- /dev/null +++ b/src/beta/realtime/ws.ts @@ -0,0 +1,96 @@ +import * as WS from 'ws'; +import { AzureOpenAI, OpenAI } from '../../index'; +import type { RealtimeClientEvent, RealtimeServerEvent } from '../../resources/beta/realtime/realtime'; +import { OpenAIRealtimeEmitter, buildRealtimeURL, isAzure } from './internal-base'; + +export class OpenAIRealtimeWS extends OpenAIRealtimeEmitter { + url: URL; + socket: WS.WebSocket; + + constructor( + props: { model: string; options?: WS.ClientOptions | undefined }, + client?: Pick, + ) { + super(); + client ??= new OpenAI(); + + this.url = buildRealtimeURL(client, props.model); + this.socket = new WS.WebSocket(this.url, { + ...props.options, + headers: { + ...props.options?.headers, + ...(isAzure(client) ? {} : { Authorization: `Bearer ${client.apiKey}` }), + 'OpenAI-Beta': 'realtime=v1', + }, + }); + + this.socket.on('message', (wsEvent) => { + const event = (() => { + try { + return JSON.parse(wsEvent.toString()) as RealtimeServerEvent; + } catch (err) { + this._onError(null, 'could not parse websocket event', err); + return null; + } + })(); + + if (event) { + this._emit('event', event); + + if (event.type === 'error') { + this._onError(event); + } else { + // @ts-expect-error TS isn't smart enough to get the relationship right here + this._emit(event.type, event); + } + } + }); + + this.socket.on('error', (err) => { + this._onError(null, err.message, err); + }); + } + + static async azure( + client: Pick, + options: { deploymentName?: string; options?: WS.ClientOptions | undefined } = {}, + ): Promise { + const deploymentName = options.deploymentName ?? client.deploymentName; + if (!deploymentName) { + throw new Error('No deployment name provided'); + } + return new OpenAIRealtimeWS( + { model: deploymentName, options: { headers: await getAzureHeaders(client) } }, + client, + ); + } + + send(event: RealtimeClientEvent) { + try { + this.socket.send(JSON.stringify(event)); + } catch (err) { + this._onError(null, 'could not send data', err); + } + } + + close(props?: { code: number; reason: string }) { + try { + this.socket.close(props?.code ?? 1000, props?.reason ?? 'OK'); + } catch (err) { + this._onError(null, 'could not close the connection', err); + } + } +} + +async function getAzureHeaders(client: Pick) { + if (client.apiKey !== '') { + return { 'api-key': client.apiKey }; + } else { + const token = await client._getAzureADToken(); + if (token) { + return { Authorization: `Bearer ${token}` }; + } else { + throw new Error('AzureOpenAI is not instantiated correctly. No API key or token provided.'); + } + } +} diff --git a/src/client.ts b/src/client.ts new file mode 100644 index 000000000..9154dc496 --- /dev/null +++ b/src/client.ts @@ -0,0 +1,1029 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import type { RequestInit, RequestInfo, BodyInit } from './internal/builtin-types'; +import type { HTTPMethod, PromiseOrValue, MergedRequestInit } from './internal/types'; +import { uuid4 } from './internal/utils/uuid'; +import { validatePositiveInteger, isAbsoluteURL, hasOwn } from './internal/utils/values'; +import { sleep } from './internal/utils/sleep'; +import { castToError, isAbortError } from './internal/errors'; +import type { APIResponseProps } from './internal/parse'; +import { getPlatformHeaders } from './internal/detect-platform'; +import * as Shims from './internal/shims'; +import * as Opts from './internal/request-options'; +import * as qs from './internal/qs'; +import { VERSION } from './version'; +import * as Errors from './error'; +import * as Pagination from './pagination'; +import { AbstractPage, type CursorPageParams, CursorPageResponse, PageResponse } from './pagination'; +import * as Uploads from './uploads'; +import * as API from './resources/index'; +import { APIPromise } from './api-promise'; +import { type Fetch } from './internal/builtin-types'; +import { isRunningInBrowser } from './internal/detect-platform'; +import { HeadersLike, NullableHeaders, buildHeaders } from './internal/headers'; +import { FinalRequestOptions, RequestOptions } from './internal/request-options'; +import { + Batch, + BatchCreateParams, + BatchError, + BatchListParams, + BatchRequestCounts, + Batches, + BatchesPage, +} from './resources/batches'; +import { + Completion, + CompletionChoice, + CompletionCreateParams, + CompletionCreateParamsNonStreaming, + CompletionCreateParamsStreaming, + CompletionUsage, + Completions, +} from './resources/completions'; +import { + CreateEmbeddingResponse, + Embedding, + EmbeddingCreateParams, + EmbeddingModel, + Embeddings, +} from './resources/embeddings'; +import { + FileContent, + FileCreateParams, + FileDeleted, + FileListParams, + FileObject, + FileObjectsPage, + FilePurpose, + Files, +} from './resources/files'; +import { + Image, + ImageCreateVariationParams, + ImageEditParams, + ImageGenerateParams, + ImageModel, + Images, + ImagesResponse, +} from './resources/images'; +import { Model, ModelDeleted, Models, ModelsPage } from './resources/models'; +import { + Moderation, + ModerationCreateParams, + ModerationCreateResponse, + ModerationImageURLInput, + ModerationModel, + ModerationMultiModalInput, + ModerationTextInput, + Moderations, +} from './resources/moderations'; +import { readEnv } from './internal/utils/env'; +import { formatRequestDetails, loggerFor } from './internal/utils/log'; +import { isEmptyObj } from './internal/utils/values'; +import { Audio, AudioModel, AudioResponseFormat } from './resources/audio/audio'; +import { Beta } from './resources/beta/beta'; +import { Chat, ChatModel } from './resources/chat/chat'; +import { FineTuning } from './resources/fine-tuning/fine-tuning'; +import { + Upload, + UploadCompleteParams, + UploadCreateParams, + Uploads as UploadsAPIUploads, +} from './resources/uploads/uploads'; +import { + ChatCompletion, + ChatCompletionAssistantMessageParam, + ChatCompletionAudio, + ChatCompletionAudioParam, + ChatCompletionChunk, + ChatCompletionContentPart, + ChatCompletionContentPartImage, + ChatCompletionContentPartInputAudio, + ChatCompletionContentPartRefusal, + ChatCompletionContentPartText, + ChatCompletionCreateParams, + ChatCompletionCreateParamsNonStreaming, + ChatCompletionCreateParamsStreaming, + ChatCompletionDeleted, + ChatCompletionDeveloperMessageParam, + ChatCompletionFunctionCallOption, + ChatCompletionFunctionMessageParam, + ChatCompletionListParams, + ChatCompletionMessage, + ChatCompletionMessageParam, + ChatCompletionMessageToolCall, + ChatCompletionModality, + ChatCompletionNamedToolChoice, + ChatCompletionPredictionContent, + ChatCompletionReasoningEffort, + ChatCompletionRole, + ChatCompletionStoreMessage, + ChatCompletionStreamOptions, + ChatCompletionSystemMessageParam, + ChatCompletionTokenLogprob, + ChatCompletionTool, + ChatCompletionToolChoiceOption, + ChatCompletionToolMessageParam, + ChatCompletionUpdateParams, + ChatCompletionUserMessageParam, + ChatCompletionsPage, +} from './resources/chat/completions/completions'; + +const safeJSON = (text: string) => { + try { + return JSON.parse(text); + } catch (err) { + return undefined; + } +}; + +type LogFn = (message: string, ...rest: unknown[]) => void; +export type Logger = { + error: LogFn; + warn: LogFn; + info: LogFn; + debug: LogFn; +}; +export type LogLevel = 'off' | 'error' | 'warn' | 'info' | 'debug'; +const parseLogLevel = ( + maybeLevel: string | undefined, + sourceName: string, + client: OpenAI, +): LogLevel | undefined => { + if (!maybeLevel) { + return undefined; + } + const levels: Record = { + off: true, + error: true, + warn: true, + info: true, + debug: true, + }; + if (hasOwn(levels, maybeLevel)) { + return maybeLevel; + } + loggerFor(client).warn( + `${sourceName} was set to ${JSON.stringify(maybeLevel)}, expected one of ${JSON.stringify( + Object.keys(levels), + )}`, + ); + return undefined; +}; + +export interface ClientOptions { + /** + * Defaults to process.env['OPENAI_API_KEY']. + */ + apiKey?: string | undefined; + + /** + * Defaults to process.env['OPENAI_ORG_ID']. + */ + organization?: string | null | undefined; + + /** + * Defaults to process.env['OPENAI_PROJECT_ID']. + */ + project?: string | null | undefined; + + /** + * Override the default base URL for the API, e.g., "https://api.example.com/v2/" + * + * Defaults to process.env['OPENAI_BASE_URL']. + */ + baseURL?: string | null | undefined; + + /** + * The maximum amount of time (in milliseconds) that the client should wait for a response + * from the server before timing out a single request. + * + * Note that request timeouts are retried by default, so in a worst-case scenario you may wait + * much longer than this timeout before the promise succeeds or fails. + */ + timeout?: number | undefined; + /** + * Additional `RequestInit` options to be passed to `fetch` calls. + * Properties will be overridden by per-request `fetchOptions`. + */ + fetchOptions?: MergedRequestInit | undefined; + + /** + * Specify a custom `fetch` function implementation. + * + * If not provided, we expect that `fetch` is defined globally. + */ + fetch?: Fetch | undefined; + + /** + * The maximum number of times that the client will retry a request in case of a + * temporary failure, like a network error or a 5XX error from the server. + * + * @default 2 + */ + maxRetries?: number | undefined; + + /** + * Default headers to include with every request to the API. + * + * These can be removed in individual requests by explicitly setting the + * header to `null` in request options. + */ + defaultHeaders?: HeadersLike | undefined; + + /** + * Default query parameters to include with every request to the API. + * + * These can be removed in individual requests by explicitly setting the + * param to `undefined` in request options. + */ + defaultQuery?: Record | undefined; + + /** + * By default, client-side use of this library is not allowed, as it risks exposing your secret API credentials to attackers. + * Only set this option to `true` if you understand the risks and have appropriate mitigations in place. + */ + dangerouslyAllowBrowser?: boolean | undefined; + + /** + * Set the log level. + * + * Defaults to process.env['OPENAI_LOG'] or 'warn' if it isn't set. + */ + logLevel?: LogLevel | undefined; + + /** + * Set the logger. + * + * Defaults to globalThis.console. + */ + logger?: Logger | undefined; +} + +type FinalizedRequestInit = RequestInit & { headers: Headers }; + +/** + * API Client for interfacing with the OpenAI API. + */ +export class OpenAI { + apiKey: string; + organization: string | null; + project: string | null; + + baseURL: string; + maxRetries: number; + timeout: number; + logger: Logger | undefined; + logLevel: LogLevel | undefined; + fetchOptions: MergedRequestInit | undefined; + + private fetch: Fetch; + #encoder: Opts.RequestEncoder; + protected idempotencyHeader?: string; + private _options: ClientOptions; + + /** + * API Client for interfacing with the OpenAI API. + * + * @param {string | undefined} [opts.apiKey=process.env['OPENAI_API_KEY'] ?? undefined] + * @param {string | null | undefined} [opts.organization=process.env['OPENAI_ORG_ID'] ?? null] + * @param {string | null | undefined} [opts.project=process.env['OPENAI_PROJECT_ID'] ?? null] + * @param {string} [opts.baseURL=process.env['OPENAI_BASE_URL'] ?? https://api.openai.com/v1] - Override the default base URL for the API. + * @param {number} [opts.timeout=10 minutes] - The maximum amount of time (in milliseconds) the client will wait for a response before timing out. + * @param {MergedRequestInit} [opts.fetchOptions] - Additional `RequestInit` options to be passed to `fetch` calls. + * @param {Fetch} [opts.fetch] - Specify a custom `fetch` function implementation. + * @param {number} [opts.maxRetries=2] - The maximum number of times the client will retry a request. + * @param {HeadersLike} opts.defaultHeaders - Default headers to include with every request to the API. + * @param {Record} opts.defaultQuery - Default query parameters to include with every request to the API. + * @param {boolean} [opts.dangerouslyAllowBrowser=false] - By default, client-side use of this library is not allowed, as it risks exposing your secret API credentials to attackers. + */ + constructor({ + baseURL = readEnv('OPENAI_BASE_URL'), + apiKey = readEnv('OPENAI_API_KEY'), + organization = readEnv('OPENAI_ORG_ID') ?? null, + project = readEnv('OPENAI_PROJECT_ID') ?? null, + ...opts + }: ClientOptions = {}) { + if (apiKey === undefined) { + throw new Errors.OpenAIError( + "The OPENAI_API_KEY environment variable is missing or empty; either provide it, or instantiate the OpenAI client with an apiKey option, like new OpenAI({ apiKey: 'My API Key' }).", + ); + } + + const options: ClientOptions = { + apiKey, + organization, + project, + ...opts, + baseURL: baseURL || `https://api.openai.com/v1`, + }; + + if (!options.dangerouslyAllowBrowser && isRunningInBrowser()) { + throw new Errors.OpenAIError( + "It looks like you're running in a browser-like environment.\n\nThis is disabled by default, as it risks exposing your secret API credentials to attackers.\nIf you understand the risks and have appropriate mitigations in place,\nyou can set the `dangerouslyAllowBrowser` option to `true`, e.g.,\n\nnew OpenAI({ apiKey, dangerouslyAllowBrowser: true });\n\nhttps://help.openai.com/en/articles/5112595-best-practices-for-api-key-safety\n", + ); + } + + this.baseURL = options.baseURL!; + this.timeout = options.timeout ?? OpenAI.DEFAULT_TIMEOUT /* 10 minutes */; + this.logger = options.logger ?? console; + const defaultLogLevel = 'warn'; + // Set default logLevel early so that we can log a warning in parseLogLevel. + this.logLevel = defaultLogLevel; + this.logLevel = + parseLogLevel(options.logLevel, 'ClientOptions.logLevel', this) ?? + parseLogLevel(readEnv('OPENAI_LOG'), "process.env['OPENAI_LOG']", this) ?? + defaultLogLevel; + this.fetchOptions = options.fetchOptions; + this.maxRetries = options.maxRetries ?? 2; + this.fetch = options.fetch ?? Shims.getDefaultFetch(); + this.#encoder = Opts.FallbackEncoder; + + this._options = options; + + this.apiKey = apiKey; + this.organization = organization; + this.project = project; + } + + protected defaultQuery(): Record | undefined { + return this._options.defaultQuery; + } + + protected validateHeaders({ values, nulls }: NullableHeaders) { + return; + } + + protected authHeaders(opts: FinalRequestOptions): Headers | undefined { + return new Headers({ Authorization: `Bearer ${this.apiKey}` }); + } + + protected stringifyQuery(query: Record): string { + return qs.stringify(query, { arrayFormat: 'brackets' }); + } + + private getUserAgent(): string { + return `${this.constructor.name}/JS ${VERSION}`; + } + + protected defaultIdempotencyKey(): string { + return `stainless-node-retry-${uuid4()}`; + } + + protected makeStatusError( + status: number, + error: Object, + message: string | undefined, + headers: Headers, + ): Errors.APIError { + return Errors.APIError.generate(status, error, message, headers); + } + + buildURL(path: string, query: Record | null | undefined): string { + const url = + isAbsoluteURL(path) ? + new URL(path) + : new URL(this.baseURL + (this.baseURL.endsWith('/') && path.startsWith('/') ? path.slice(1) : path)); + + const defaultQuery = this.defaultQuery(); + if (!isEmptyObj(defaultQuery)) { + query = { ...defaultQuery, ...query }; + } + + if (typeof query === 'object' && query && !Array.isArray(query)) { + url.search = this.stringifyQuery(query as Record); + } + + return url.toString(); + } + + /** + * Used as a callback for mutating the given `FinalRequestOptions` object. + */ + protected async prepareOptions(options: FinalRequestOptions): Promise {} + + /** + * Used as a callback for mutating the given `RequestInit` object. + * + * This is useful for cases where you want to add certain headers based off of + * the request properties, e.g. `method` or `url`. + */ + protected async prepareRequest( + request: RequestInit, + { url, options }: { url: string; options: FinalRequestOptions }, + ): Promise {} + + get(path: string, opts?: PromiseOrValue): APIPromise { + return this.methodRequest('get', path, opts); + } + + post(path: string, opts?: PromiseOrValue): APIPromise { + return this.methodRequest('post', path, opts); + } + + patch(path: string, opts?: PromiseOrValue): APIPromise { + return this.methodRequest('patch', path, opts); + } + + put(path: string, opts?: PromiseOrValue): APIPromise { + return this.methodRequest('put', path, opts); + } + + delete(path: string, opts?: PromiseOrValue): APIPromise { + return this.methodRequest('delete', path, opts); + } + + private methodRequest( + method: HTTPMethod, + path: string, + opts?: PromiseOrValue, + ): APIPromise { + return this.request( + Promise.resolve(opts).then((opts) => { + return { method, path, ...opts }; + }), + ); + } + + request( + options: PromiseOrValue, + remainingRetries: number | null = null, + ): APIPromise { + return new APIPromise(this, this.makeRequest(options, remainingRetries, undefined)); + } + + private async makeRequest( + optionsInput: PromiseOrValue, + retriesRemaining: number | null, + retryOfRequestLogID: string | undefined, + ): Promise { + const options = await optionsInput; + const maxRetries = options.maxRetries ?? this.maxRetries; + if (retriesRemaining == null) { + retriesRemaining = maxRetries; + } + + await this.prepareOptions(options); + + const { req, url, timeout } = this.buildRequest(options, { retryCount: maxRetries - retriesRemaining }); + + await this.prepareRequest(req, { url, options }); + + /** Not an API request ID, just for correlating local log entries. */ + const requestLogID = 'log_' + ((Math.random() * (1 << 24)) | 0).toString(16).padStart(6, '0'); + const retryLogStr = retryOfRequestLogID === undefined ? '' : `, retryOf: ${retryOfRequestLogID}`; + const startTime = Date.now(); + + loggerFor(this).debug( + `[${requestLogID}] sending request`, + formatRequestDetails({ + retryOfRequestLogID, + method: options.method, + url, + options, + headers: req.headers, + }), + ); + + if (options.signal?.aborted) { + throw new Errors.APIUserAbortError(); + } + + const controller = new AbortController(); + const response = await this.fetchWithTimeout(url, req, timeout, controller).catch(castToError); + const headersTime = Date.now(); + + if (response instanceof Error) { + const retryMessage = `retrying, ${retriesRemaining} attempts remaining`; + if (options.signal?.aborted) { + throw new Errors.APIUserAbortError(); + } + // detect native connection timeout errors + // deno throws "TypeError: error sending request for url (https://example/): client error (Connect): tcp connect error: Operation timed out (os error 60): Operation timed out (os error 60)" + // undici throws "TypeError: fetch failed" with cause "ConnectTimeoutError: Connect Timeout Error (attempted address: example:443, timeout: 1ms)" + // others do not provide enough information to distinguish timeouts from other connection errors + const isTimeout = + isAbortError(response) || + /timed? ?out/i.test(String(response) + ('cause' in response ? String(response.cause) : '')); + if (retriesRemaining) { + loggerFor(this).info( + `[${requestLogID}] connection ${isTimeout ? 'timed out' : 'failed'} - ${retryMessage}`, + ); + loggerFor(this).debug( + `[${requestLogID}] connection ${isTimeout ? 'timed out' : 'failed'} (${retryMessage})`, + formatRequestDetails({ + retryOfRequestLogID, + url, + durationMs: headersTime - startTime, + message: response.message, + }), + ); + return this.retryRequest(options, retriesRemaining, retryOfRequestLogID ?? requestLogID); + } + loggerFor(this).info( + `[${requestLogID}] connection ${isTimeout ? 'timed out' : 'failed'} - error; no more retries left`, + ); + loggerFor(this).debug( + `[${requestLogID}] connection ${isTimeout ? 'timed out' : 'failed'} (error; no more retries left)`, + formatRequestDetails({ + retryOfRequestLogID, + url, + durationMs: headersTime - startTime, + message: response.message, + }), + ); + if (isTimeout) { + throw new Errors.APIConnectionTimeoutError(); + } + throw new Errors.APIConnectionError({ cause: response }); + } + + const specialHeaders = [...response.headers.entries()] + .filter(([name]) => name === 'x-request-id') + .map(([name, value]) => ', ' + name + ': ' + JSON.stringify(value)) + .join(''); + const responseInfo = `[${requestLogID}${retryLogStr}${specialHeaders}] ${req.method} ${url} ${ + response.ok ? 'succeeded' : 'failed' + } with status ${response.status} in ${headersTime - startTime}ms`; + + if (!response.ok) { + const shouldRetry = this.shouldRetry(response); + if (retriesRemaining && shouldRetry) { + const retryMessage = `retrying, ${retriesRemaining} attempts remaining`; + + // We don't need the body of this response. + await Shims.CancelReadableStream(response.body); + loggerFor(this).info(`${responseInfo} - ${retryMessage}`); + loggerFor(this).debug( + `[${requestLogID}] response error (${retryMessage})`, + formatRequestDetails({ + retryOfRequestLogID, + url: response.url, + status: response.status, + headers: response.headers, + durationMs: headersTime - startTime, + }), + ); + return this.retryRequest( + options, + retriesRemaining, + retryOfRequestLogID ?? requestLogID, + response.headers, + ); + } + + const retryMessage = shouldRetry ? `error; no more retries left` : `error; not retryable`; + + loggerFor(this).info(`${responseInfo} - ${retryMessage}`); + + const errText = await response.text().catch((err: any) => castToError(err).message); + const errJSON = safeJSON(errText); + const errMessage = errJSON ? undefined : errText; + + loggerFor(this).debug( + `[${requestLogID}] response error (${retryMessage})`, + formatRequestDetails({ + retryOfRequestLogID, + url: response.url, + status: response.status, + headers: response.headers, + message: errMessage, + durationMs: Date.now() - startTime, + }), + ); + + const err = this.makeStatusError(response.status, errJSON, errMessage, response.headers); + throw err; + } + + loggerFor(this).info(responseInfo); + loggerFor(this).debug( + `[${requestLogID}] response start`, + formatRequestDetails({ + retryOfRequestLogID, + url: response.url, + status: response.status, + headers: response.headers, + durationMs: headersTime - startTime, + }), + ); + + return { response, options, controller, requestLogID, retryOfRequestLogID, startTime }; + } + + getAPIList = Pagination.AbstractPage>( + path: string, + Page: new (...args: any[]) => PageClass, + opts?: RequestOptions, + ): Pagination.PagePromise { + return this.requestAPIList(Page, { method: 'get', path, ...opts }); + } + + requestAPIList< + Item = unknown, + PageClass extends Pagination.AbstractPage = Pagination.AbstractPage, + >( + Page: new (...args: ConstructorParameters) => PageClass, + options: FinalRequestOptions, + ): Pagination.PagePromise { + const request = this.makeRequest(options, null, undefined); + return new Pagination.PagePromise(this as any as OpenAI, request, Page); + } + + async fetchWithTimeout( + url: RequestInfo, + init: RequestInit | undefined, + ms: number, + controller: AbortController, + ): Promise { + const { signal, method, ...options } = init || {}; + if (signal) signal.addEventListener('abort', () => controller.abort()); + + const timeout = setTimeout(() => controller.abort(), ms); + + const isReadableBody = + ((globalThis as any).ReadableStream && options.body instanceof (globalThis as any).ReadableStream) || + (typeof options.body === 'object' && options.body !== null && Symbol.asyncIterator in options.body); + + const fetchOptions: RequestInit = { + signal: controller.signal as any, + ...(isReadableBody ? { duplex: 'half' } : {}), + method: 'GET', + ...options, + }; + if (method) { + // Custom methods like 'patch' need to be uppercased + // See https://github.com/nodejs/undici/issues/2294 + fetchOptions.method = method.toUpperCase(); + } + + return ( + // use undefined this binding; fetch errors if bound to something else in browser/cloudflare + this.fetch.call(undefined, url, fetchOptions).finally(() => { + clearTimeout(timeout); + }) + ); + } + + private shouldRetry(response: Response): boolean { + // Note this is not a standard header. + const shouldRetryHeader = response.headers.get('x-should-retry'); + + // If the server explicitly says whether or not to retry, obey. + if (shouldRetryHeader === 'true') return true; + if (shouldRetryHeader === 'false') return false; + + // Retry on request timeouts. + if (response.status === 408) return true; + + // Retry on lock timeouts. + if (response.status === 409) return true; + + // Retry on rate limits. + if (response.status === 429) return true; + + // Retry internal errors. + if (response.status >= 500) return true; + + return false; + } + + private async retryRequest( + options: FinalRequestOptions, + retriesRemaining: number, + requestLogID: string, + responseHeaders?: Headers | undefined, + ): Promise { + let timeoutMillis: number | undefined; + + // Note the `retry-after-ms` header may not be standard, but is a good idea and we'd like proactive support for it. + const retryAfterMillisHeader = responseHeaders?.get('retry-after-ms'); + if (retryAfterMillisHeader) { + const timeoutMs = parseFloat(retryAfterMillisHeader); + if (!Number.isNaN(timeoutMs)) { + timeoutMillis = timeoutMs; + } + } + + // About the Retry-After header: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After + const retryAfterHeader = responseHeaders?.get('retry-after'); + if (retryAfterHeader && !timeoutMillis) { + const timeoutSeconds = parseFloat(retryAfterHeader); + if (!Number.isNaN(timeoutSeconds)) { + timeoutMillis = timeoutSeconds * 1000; + } else { + timeoutMillis = Date.parse(retryAfterHeader) - Date.now(); + } + } + + // If the API asks us to wait a certain amount of time (and it's a reasonable amount), + // just do what it says, but otherwise calculate a default + if (!(timeoutMillis && 0 <= timeoutMillis && timeoutMillis < 60 * 1000)) { + const maxRetries = options.maxRetries ?? this.maxRetries; + timeoutMillis = this.calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries); + } + await sleep(timeoutMillis); + + return this.makeRequest(options, retriesRemaining - 1, requestLogID); + } + + private calculateDefaultRetryTimeoutMillis(retriesRemaining: number, maxRetries: number): number { + const initialRetryDelay = 0.5; + const maxRetryDelay = 8.0; + + const numRetries = maxRetries - retriesRemaining; + + // Apply exponential backoff, but not more than the max. + const sleepSeconds = Math.min(initialRetryDelay * Math.pow(2, numRetries), maxRetryDelay); + + // Apply some jitter, take up to at most 25 percent of the retry time. + const jitter = 1 - Math.random() * 0.25; + + return sleepSeconds * jitter * 1000; + } + + buildRequest( + options: FinalRequestOptions, + { retryCount = 0 }: { retryCount?: number } = {}, + ): { req: FinalizedRequestInit; url: string; timeout: number } { + options = { ...options }; + const { method, path, query } = options; + + const url = this.buildURL(path!, query as Record); + if ('timeout' in options) validatePositiveInteger('timeout', options.timeout); + options.timeout = options.timeout ?? this.timeout; + const { bodyHeaders, body } = this.buildBody({ options }); + const reqHeaders = this.buildHeaders({ options, method, bodyHeaders, retryCount }); + + const req: FinalizedRequestInit = { + method, + headers: reqHeaders, + ...(options.signal && { signal: options.signal }), + ...((globalThis as any).ReadableStream && + body instanceof (globalThis as any).ReadableStream && { duplex: 'half' }), + ...(body && { body }), + ...((this.fetchOptions as any) ?? {}), + ...((options.fetchOptions as any) ?? {}), + }; + + return { req, url, timeout: options.timeout }; + } + + private buildHeaders({ + options, + method, + bodyHeaders, + retryCount, + }: { + options: FinalRequestOptions; + method: HTTPMethod; + bodyHeaders: HeadersLike; + retryCount: number; + }): Headers { + let idempotencyHeaders: HeadersLike = {}; + if (this.idempotencyHeader && method !== 'get') { + if (!options.idempotencyKey) options.idempotencyKey = this.defaultIdempotencyKey(); + idempotencyHeaders[this.idempotencyHeader] = options.idempotencyKey; + } + + const headers = buildHeaders([ + idempotencyHeaders, + { + Accept: 'application/json', + 'User-Agent': this.getUserAgent(), + 'X-Stainless-Retry-Count': String(retryCount), + ...(options.timeout ? { 'X-Stainless-Timeout': String(options.timeout) } : {}), + ...getPlatformHeaders(), + 'OpenAI-Organization': this.organization, + 'OpenAI-Project': this.project, + }, + this.authHeaders(options), + this._options.defaultHeaders, + bodyHeaders, + options.headers, + ]); + + this.validateHeaders(headers); + + return headers.values; + } + + private buildBody({ options: { body, headers: rawHeaders } }: { options: FinalRequestOptions }): { + bodyHeaders: HeadersLike; + body: BodyInit | undefined; + } { + if (!body) { + return { bodyHeaders: undefined, body: undefined }; + } + const headers = buildHeaders([rawHeaders]); + if ( + // Pass raw type verbatim + ArrayBuffer.isView(body) || + body instanceof ArrayBuffer || + body instanceof DataView || + (typeof body === 'string' && + // Preserve legacy string encoding behavior for now + headers.values.has('content-type')) || + // `Blob` is superset of `File` + body instanceof Blob || + // `FormData` -> `multipart/form-data` + body instanceof FormData || + // `URLSearchParams` -> `application/x-www-form-urlencoded` + body instanceof URLSearchParams || + // Send chunked stream (each chunk has own `length`) + ((globalThis as any).ReadableStream && body instanceof (globalThis as any).ReadableStream) + ) { + return { bodyHeaders: undefined, body: body as BodyInit }; + } else if ( + typeof body === 'object' && + (Symbol.asyncIterator in body || + (Symbol.iterator in body && 'next' in body && typeof body.next === 'function')) + ) { + return { bodyHeaders: undefined, body: Shims.ReadableStreamFrom(body as AsyncIterable) }; + } else { + return this.#encoder({ body, headers }); + } + } + + static OpenAI = this; + static DEFAULT_TIMEOUT = 600000; // 10 minutes + + static OpenAIError = Errors.OpenAIError; + static APIError = Errors.APIError; + static APIConnectionError = Errors.APIConnectionError; + static APIConnectionTimeoutError = Errors.APIConnectionTimeoutError; + static APIUserAbortError = Errors.APIUserAbortError; + static NotFoundError = Errors.NotFoundError; + static ConflictError = Errors.ConflictError; + static RateLimitError = Errors.RateLimitError; + static BadRequestError = Errors.BadRequestError; + static AuthenticationError = Errors.AuthenticationError; + static InternalServerError = Errors.InternalServerError; + static PermissionDeniedError = Errors.PermissionDeniedError; + static UnprocessableEntityError = Errors.UnprocessableEntityError; + + static toFile = Uploads.toFile; + + completions: API.Completions = new API.Completions(this); + chat: API.Chat = new API.Chat(this); + embeddings: API.Embeddings = new API.Embeddings(this); + files: API.Files = new API.Files(this); + images: API.Images = new API.Images(this); + audio: API.Audio = new API.Audio(this); + moderations: API.Moderations = new API.Moderations(this); + models: API.Models = new API.Models(this); + fineTuning: API.FineTuning = new API.FineTuning(this); + beta: API.Beta = new API.Beta(this); + batches: API.Batches = new API.Batches(this); + uploads: API.Uploads = new API.Uploads(this); +} +OpenAI.Completions = Completions; +OpenAI.Chat = Chat; +OpenAI.Embeddings = Embeddings; +OpenAI.Files = Files; +OpenAI.Images = Images; +OpenAI.Audio = Audio; +OpenAI.Moderations = Moderations; +OpenAI.Models = Models; +OpenAI.FineTuning = FineTuning; +OpenAI.Beta = Beta; +OpenAI.Batches = Batches; +OpenAI.Uploads = UploadsAPIUploads; +export declare namespace OpenAI { + export type RequestOptions = Opts.RequestOptions; + + export import Page = Pagination.Page; + export { type PageResponse as PageResponse }; + + export import CursorPage = Pagination.CursorPage; + export { type CursorPageParams as CursorPageParams, type CursorPageResponse as CursorPageResponse }; + + export { + Completions as Completions, + type Completion as Completion, + type CompletionChoice as CompletionChoice, + type CompletionUsage as CompletionUsage, + type CompletionCreateParams as CompletionCreateParams, + type CompletionCreateParamsNonStreaming as CompletionCreateParamsNonStreaming, + type CompletionCreateParamsStreaming as CompletionCreateParamsStreaming, + }; + + export { + Chat as Chat, + type ChatModel as ChatModel, + type ChatCompletion as ChatCompletion, + type ChatCompletionAssistantMessageParam as ChatCompletionAssistantMessageParam, + type ChatCompletionAudio as ChatCompletionAudio, + type ChatCompletionAudioParam as ChatCompletionAudioParam, + type ChatCompletionChunk as ChatCompletionChunk, + type ChatCompletionContentPart as ChatCompletionContentPart, + type ChatCompletionContentPartImage as ChatCompletionContentPartImage, + type ChatCompletionContentPartInputAudio as ChatCompletionContentPartInputAudio, + type ChatCompletionContentPartRefusal as ChatCompletionContentPartRefusal, + type ChatCompletionContentPartText as ChatCompletionContentPartText, + type ChatCompletionDeleted as ChatCompletionDeleted, + type ChatCompletionDeveloperMessageParam as ChatCompletionDeveloperMessageParam, + type ChatCompletionFunctionCallOption as ChatCompletionFunctionCallOption, + type ChatCompletionFunctionMessageParam as ChatCompletionFunctionMessageParam, + type ChatCompletionMessage as ChatCompletionMessage, + type ChatCompletionMessageParam as ChatCompletionMessageParam, + type ChatCompletionMessageToolCall as ChatCompletionMessageToolCall, + type ChatCompletionModality as ChatCompletionModality, + type ChatCompletionNamedToolChoice as ChatCompletionNamedToolChoice, + type ChatCompletionPredictionContent as ChatCompletionPredictionContent, + type ChatCompletionReasoningEffort as ChatCompletionReasoningEffort, + type ChatCompletionRole as ChatCompletionRole, + type ChatCompletionStoreMessage as ChatCompletionStoreMessage, + type ChatCompletionStreamOptions as ChatCompletionStreamOptions, + type ChatCompletionSystemMessageParam as ChatCompletionSystemMessageParam, + type ChatCompletionTokenLogprob as ChatCompletionTokenLogprob, + type ChatCompletionTool as ChatCompletionTool, + type ChatCompletionToolChoiceOption as ChatCompletionToolChoiceOption, + type ChatCompletionToolMessageParam as ChatCompletionToolMessageParam, + type ChatCompletionUserMessageParam as ChatCompletionUserMessageParam, + type ChatCompletionsPage as ChatCompletionsPage, + type ChatCompletionCreateParams as ChatCompletionCreateParams, + type ChatCompletionCreateParamsNonStreaming as ChatCompletionCreateParamsNonStreaming, + type ChatCompletionCreateParamsStreaming as ChatCompletionCreateParamsStreaming, + type ChatCompletionUpdateParams as ChatCompletionUpdateParams, + type ChatCompletionListParams as ChatCompletionListParams, + }; + + export { + Embeddings as Embeddings, + type CreateEmbeddingResponse as CreateEmbeddingResponse, + type Embedding as Embedding, + type EmbeddingModel as EmbeddingModel, + type EmbeddingCreateParams as EmbeddingCreateParams, + }; + + export { + Files as Files, + type FileContent as FileContent, + type FileDeleted as FileDeleted, + type FileObject as FileObject, + type FilePurpose as FilePurpose, + type FileObjectsPage as FileObjectsPage, + type FileCreateParams as FileCreateParams, + type FileListParams as FileListParams, + }; + + export { + Images as Images, + type Image as Image, + type ImageModel as ImageModel, + type ImagesResponse as ImagesResponse, + type ImageCreateVariationParams as ImageCreateVariationParams, + type ImageEditParams as ImageEditParams, + type ImageGenerateParams as ImageGenerateParams, + }; + + export { Audio as Audio, type AudioModel as AudioModel, type AudioResponseFormat as AudioResponseFormat }; + + export { + Moderations as Moderations, + type Moderation as Moderation, + type ModerationImageURLInput as ModerationImageURLInput, + type ModerationModel as ModerationModel, + type ModerationMultiModalInput as ModerationMultiModalInput, + type ModerationTextInput as ModerationTextInput, + type ModerationCreateResponse as ModerationCreateResponse, + type ModerationCreateParams as ModerationCreateParams, + }; + + export { + Models as Models, + type Model as Model, + type ModelDeleted as ModelDeleted, + type ModelsPage as ModelsPage, + }; + + export { FineTuning as FineTuning }; + + export { Beta as Beta }; + + export { + Batches as Batches, + type Batch as Batch, + type BatchError as BatchError, + type BatchRequestCounts as BatchRequestCounts, + type BatchesPage as BatchesPage, + type BatchCreateParams as BatchCreateParams, + type BatchListParams as BatchListParams, + }; + + export { + UploadsAPIUploads as Uploads, + type Upload as Upload, + type UploadCreateParams as UploadCreateParams, + type UploadCompleteParams as UploadCompleteParams, + }; + + export type ErrorObject = API.ErrorObject; + export type FunctionDefinition = API.FunctionDefinition; + export type FunctionParameters = API.FunctionParameters; + export type Metadata = API.Metadata; + export type ResponseFormatJSONObject = API.ResponseFormatJSONObject; + export type ResponseFormatJSONSchema = API.ResponseFormatJSONSchema; + export type ResponseFormatText = API.ResponseFormatText; +} diff --git a/src/core.ts b/src/core.ts deleted file mode 100644 index 68f1e676a..000000000 --- a/src/core.ts +++ /dev/null @@ -1,1233 +0,0 @@ -import { VERSION } from './version'; -import { Stream } from './streaming'; -import { - OpenAIError, - APIError, - APIConnectionError, - APIConnectionTimeoutError, - APIUserAbortError, -} from './error'; -import { - kind as shimsKind, - type Readable, - getDefaultAgent, - type Agent, - fetch, - type RequestInfo, - type RequestInit, - type Response, - type HeadersInit, -} from './_shims/index'; -export { type Response }; -import { BlobLike, isBlobLike, isMultipartBody } from './uploads'; -export { - maybeMultipartFormRequestOptions, - multipartFormRequestOptions, - createForm, - type Uploadable, -} from './uploads'; - -export type Fetch = (url: RequestInfo, init?: RequestInit) => Promise; - -type PromiseOrValue = T | Promise; - -type APIResponseProps = { - response: Response; - options: FinalRequestOptions; - controller: AbortController; -}; - -async function defaultParseResponse(props: APIResponseProps): Promise> { - const { response } = props; - if (props.options.stream) { - debug('response', response.status, response.url, response.headers, response.body); - - // Note: there is an invariant here that isn't represented in the type system - // that if you set `stream: true` the response type must also be `Stream` - - if (props.options.__streamClass) { - return props.options.__streamClass.fromSSEResponse(response, props.controller) as any; - } - - return Stream.fromSSEResponse(response, props.controller) as any; - } - - // fetch refuses to read the body when the status code is 204. - if (response.status === 204) { - return null as WithRequestID; - } - - if (props.options.__binaryResponse) { - return response as unknown as WithRequestID; - } - - const contentType = response.headers.get('content-type'); - const isJSON = - contentType?.includes('application/json') || contentType?.includes('application/vnd.api+json'); - if (isJSON) { - const json = await response.json(); - - debug('response', response.status, response.url, response.headers, json); - - return _addRequestID(json, response); - } - - const text = await response.text(); - debug('response', response.status, response.url, response.headers, text); - - // TODO handle blob, arraybuffer, other content types, etc. - return text as unknown as WithRequestID; -} - -type WithRequestID = - T extends Array | Response | AbstractPage ? T - : T extends Record ? T & { _request_id?: string | null } - : T; - -function _addRequestID(value: T, response: Response): WithRequestID { - if (!value || typeof value !== 'object' || Array.isArray(value)) { - return value as WithRequestID; - } - - return Object.defineProperty(value, '_request_id', { - value: response.headers.get('x-request-id'), - enumerable: false, - }) as WithRequestID; -} - -/** - * A subclass of `Promise` providing additional helper methods - * for interacting with the SDK. - */ -export class APIPromise extends Promise> { - private parsedPromise: Promise> | undefined; - - constructor( - private responsePromise: Promise, - private parseResponse: ( - props: APIResponseProps, - ) => PromiseOrValue> = defaultParseResponse, - ) { - super((resolve) => { - // this is maybe a bit weird but this has to be a no-op to not implicitly - // parse the response body; instead .then, .catch, .finally are overridden - // to parse the response - resolve(null as any); - }); - } - - _thenUnwrap(transform: (data: T, props: APIResponseProps) => U): APIPromise { - return new APIPromise(this.responsePromise, async (props) => - _addRequestID(transform(await this.parseResponse(props), props), props.response), - ); - } - - /** - * Gets the raw `Response` instance instead of parsing the response - * data. - * - * If you want to parse the response body but still get the `Response` - * instance, you can use {@link withResponse()}. - * - * 👋 Getting the wrong TypeScript type for `Response`? - * Try setting `"moduleResolution": "NodeNext"` if you can, - * or add one of these imports before your first `import … from 'openai'`: - * - `import 'openai/shims/node'` (if you're running on Node) - * - `import 'openai/shims/web'` (otherwise) - */ - asResponse(): Promise { - return this.responsePromise.then((p) => p.response); - } - - /** - * Gets the parsed response data, the raw `Response` instance and the ID of the request, - * returned via the X-Request-ID header which is useful for debugging requests and reporting - * issues to OpenAI. - * - * If you just want to get the raw `Response` instance without parsing it, - * you can use {@link asResponse()}. - * - * - * 👋 Getting the wrong TypeScript type for `Response`? - * Try setting `"moduleResolution": "NodeNext"` if you can, - * or add one of these imports before your first `import … from 'openai'`: - * - `import 'openai/shims/node'` (if you're running on Node) - * - `import 'openai/shims/web'` (otherwise) - */ - async withResponse(): Promise<{ data: T; response: Response; request_id: string | null | undefined }> { - const [data, response] = await Promise.all([this.parse(), this.asResponse()]); - return { data, response, request_id: response.headers.get('x-request-id') }; - } - - private parse(): Promise> { - if (!this.parsedPromise) { - this.parsedPromise = this.responsePromise.then(this.parseResponse) as any as Promise>; - } - return this.parsedPromise; - } - - override then, TResult2 = never>( - onfulfilled?: ((value: WithRequestID) => TResult1 | PromiseLike) | undefined | null, - onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null, - ): Promise { - return this.parse().then(onfulfilled, onrejected); - } - - override catch( - onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null, - ): Promise | TResult> { - return this.parse().catch(onrejected); - } - - override finally(onfinally?: (() => void) | undefined | null): Promise> { - return this.parse().finally(onfinally); - } -} - -export abstract class APIClient { - baseURL: string; - maxRetries: number; - timeout: number; - httpAgent: Agent | undefined; - - private fetch: Fetch; - protected idempotencyHeader?: string; - - constructor({ - baseURL, - maxRetries = 2, - timeout = 600000, // 10 minutes - httpAgent, - fetch: overriddenFetch, - }: { - baseURL: string; - maxRetries?: number | undefined; - timeout: number | undefined; - httpAgent: Agent | undefined; - fetch: Fetch | undefined; - }) { - this.baseURL = baseURL; - this.maxRetries = validatePositiveInteger('maxRetries', maxRetries); - this.timeout = validatePositiveInteger('timeout', timeout); - this.httpAgent = httpAgent; - - this.fetch = overriddenFetch ?? fetch; - } - - protected authHeaders(opts: FinalRequestOptions): Headers { - return {}; - } - - /** - * Override this to add your own default headers, for example: - * - * { - * ...super.defaultHeaders(), - * Authorization: 'Bearer 123', - * } - */ - protected defaultHeaders(opts: FinalRequestOptions): Headers { - return { - Accept: 'application/json', - 'Content-Type': 'application/json', - 'User-Agent': this.getUserAgent(), - ...getPlatformHeaders(), - ...this.authHeaders(opts), - }; - } - - protected abstract defaultQuery(): DefaultQuery | undefined; - - /** - * Override this to add your own headers validation: - */ - protected validateHeaders(headers: Headers, customHeaders: Headers) {} - - protected defaultIdempotencyKey(): string { - return `stainless-node-retry-${uuid4()}`; - } - - get(path: string, opts?: PromiseOrValue>): APIPromise { - return this.methodRequest('get', path, opts); - } - - post(path: string, opts?: PromiseOrValue>): APIPromise { - return this.methodRequest('post', path, opts); - } - - patch(path: string, opts?: PromiseOrValue>): APIPromise { - return this.methodRequest('patch', path, opts); - } - - put(path: string, opts?: PromiseOrValue>): APIPromise { - return this.methodRequest('put', path, opts); - } - - delete(path: string, opts?: PromiseOrValue>): APIPromise { - return this.methodRequest('delete', path, opts); - } - - private methodRequest( - method: HTTPMethod, - path: string, - opts?: PromiseOrValue>, - ): APIPromise { - return this.request( - Promise.resolve(opts).then(async (opts) => { - const body = - opts && isBlobLike(opts?.body) ? new DataView(await opts.body.arrayBuffer()) - : opts?.body instanceof DataView ? opts.body - : opts?.body instanceof ArrayBuffer ? new DataView(opts.body) - : opts && ArrayBuffer.isView(opts?.body) ? new DataView(opts.body.buffer) - : opts?.body; - return { method, path, ...opts, body }; - }), - ); - } - - getAPIList = AbstractPage>( - path: string, - Page: new (...args: any[]) => PageClass, - opts?: RequestOptions, - ): PagePromise { - return this.requestAPIList(Page, { method: 'get', path, ...opts }); - } - - private calculateContentLength(body: unknown): string | null { - if (typeof body === 'string') { - if (typeof Buffer !== 'undefined') { - return Buffer.byteLength(body, 'utf8').toString(); - } - - if (typeof TextEncoder !== 'undefined') { - const encoder = new TextEncoder(); - const encoded = encoder.encode(body); - return encoded.length.toString(); - } - } else if (ArrayBuffer.isView(body)) { - return body.byteLength.toString(); - } - - return null; - } - - buildRequest( - options: FinalRequestOptions, - { retryCount = 0 }: { retryCount?: number } = {}, - ): { req: RequestInit; url: string; timeout: number } { - const { method, path, query, headers: headers = {} } = options; - - const body = - ArrayBuffer.isView(options.body) || (options.__binaryRequest && typeof options.body === 'string') ? - options.body - : isMultipartBody(options.body) ? options.body.body - : options.body ? JSON.stringify(options.body, null, 2) - : null; - const contentLength = this.calculateContentLength(body); - - const url = this.buildURL(path!, query); - if ('timeout' in options) validatePositiveInteger('timeout', options.timeout); - const timeout = options.timeout ?? this.timeout; - const httpAgent = options.httpAgent ?? this.httpAgent ?? getDefaultAgent(url); - const minAgentTimeout = timeout + 1000; - if ( - typeof (httpAgent as any)?.options?.timeout === 'number' && - minAgentTimeout > ((httpAgent as any).options.timeout ?? 0) - ) { - // Allow any given request to bump our agent active socket timeout. - // This may seem strange, but leaking active sockets should be rare and not particularly problematic, - // and without mutating agent we would need to create more of them. - // This tradeoff optimizes for performance. - (httpAgent as any).options.timeout = minAgentTimeout; - } - - if (this.idempotencyHeader && method !== 'get') { - if (!options.idempotencyKey) options.idempotencyKey = this.defaultIdempotencyKey(); - headers[this.idempotencyHeader] = options.idempotencyKey; - } - - const reqHeaders = this.buildHeaders({ options, headers, contentLength, retryCount }); - - const req: RequestInit = { - method, - ...(body && { body: body as any }), - headers: reqHeaders, - ...(httpAgent && { agent: httpAgent }), - // @ts-ignore node-fetch uses a custom AbortSignal type that is - // not compatible with standard web types - signal: options.signal ?? null, - }; - - return { req, url, timeout }; - } - - private buildHeaders({ - options, - headers, - contentLength, - retryCount, - }: { - options: FinalRequestOptions; - headers: Record; - contentLength: string | null | undefined; - retryCount: number; - }): Record { - const reqHeaders: Record = {}; - if (contentLength) { - reqHeaders['content-length'] = contentLength; - } - - const defaultHeaders = this.defaultHeaders(options); - applyHeadersMut(reqHeaders, defaultHeaders); - applyHeadersMut(reqHeaders, headers); - - // let builtin fetch set the Content-Type for multipart bodies - if (isMultipartBody(options.body) && shimsKind !== 'node') { - delete reqHeaders['content-type']; - } - - // Don't set the retry count header if it was already set or removed through default headers or by the - // caller. We check `defaultHeaders` and `headers`, which can contain nulls, instead of `reqHeaders` to - // account for the removal case. - if ( - getHeader(defaultHeaders, 'x-stainless-retry-count') === undefined && - getHeader(headers, 'x-stainless-retry-count') === undefined - ) { - reqHeaders['x-stainless-retry-count'] = String(retryCount); - } - - this.validateHeaders(reqHeaders, headers); - - return reqHeaders; - } - - /** - * Used as a callback for mutating the given `FinalRequestOptions` object. - */ - protected async prepareOptions(options: FinalRequestOptions): Promise {} - - /** - * Used as a callback for mutating the given `RequestInit` object. - * - * This is useful for cases where you want to add certain headers based off of - * the request properties, e.g. `method` or `url`. - */ - protected async prepareRequest( - request: RequestInit, - { url, options }: { url: string; options: FinalRequestOptions }, - ): Promise {} - - protected parseHeaders(headers: HeadersInit | null | undefined): Record { - return ( - !headers ? {} - : Symbol.iterator in headers ? - Object.fromEntries(Array.from(headers as Iterable).map((header) => [...header])) - : { ...headers } - ); - } - - protected makeStatusError( - status: number | undefined, - error: Object | undefined, - message: string | undefined, - headers: Headers | undefined, - ): APIError { - return APIError.generate(status, error, message, headers); - } - - request( - options: PromiseOrValue>, - remainingRetries: number | null = null, - ): APIPromise { - return new APIPromise(this.makeRequest(options, remainingRetries)); - } - - private async makeRequest( - optionsInput: PromiseOrValue>, - retriesRemaining: number | null, - ): Promise { - const options = await optionsInput; - const maxRetries = options.maxRetries ?? this.maxRetries; - if (retriesRemaining == null) { - retriesRemaining = maxRetries; - } - - await this.prepareOptions(options); - - const { req, url, timeout } = this.buildRequest(options, { retryCount: maxRetries - retriesRemaining }); - - await this.prepareRequest(req, { url, options }); - - debug('request', url, options, req.headers); - - if (options.signal?.aborted) { - throw new APIUserAbortError(); - } - - const controller = new AbortController(); - const response = await this.fetchWithTimeout(url, req, timeout, controller).catch(castToError); - - if (response instanceof Error) { - if (options.signal?.aborted) { - throw new APIUserAbortError(); - } - if (retriesRemaining) { - return this.retryRequest(options, retriesRemaining); - } - if (response.name === 'AbortError') { - throw new APIConnectionTimeoutError(); - } - throw new APIConnectionError({ cause: response }); - } - - const responseHeaders = createResponseHeaders(response.headers); - - if (!response.ok) { - if (retriesRemaining && this.shouldRetry(response)) { - const retryMessage = `retrying, ${retriesRemaining} attempts remaining`; - debug(`response (error; ${retryMessage})`, response.status, url, responseHeaders); - return this.retryRequest(options, retriesRemaining, responseHeaders); - } - - const errText = await response.text().catch((e) => castToError(e).message); - const errJSON = safeJSON(errText); - const errMessage = errJSON ? undefined : errText; - const retryMessage = retriesRemaining ? `(error; no more retries left)` : `(error; not retryable)`; - - debug(`response (error; ${retryMessage})`, response.status, url, responseHeaders, errMessage); - - const err = this.makeStatusError(response.status, errJSON, errMessage, responseHeaders); - throw err; - } - - return { response, options, controller }; - } - - requestAPIList = AbstractPage>( - Page: new (...args: ConstructorParameters) => PageClass, - options: FinalRequestOptions, - ): PagePromise { - const request = this.makeRequest(options, null); - return new PagePromise(this, request, Page); - } - - buildURL(path: string, query: Req | null | undefined): string { - const url = - isAbsoluteURL(path) ? - new URL(path) - : new URL(this.baseURL + (this.baseURL.endsWith('/') && path.startsWith('/') ? path.slice(1) : path)); - - const defaultQuery = this.defaultQuery(); - if (!isEmptyObj(defaultQuery)) { - query = { ...defaultQuery, ...query } as Req; - } - - if (typeof query === 'object' && query && !Array.isArray(query)) { - url.search = this.stringifyQuery(query as Record); - } - - return url.toString(); - } - - protected stringifyQuery(query: Record): string { - return Object.entries(query) - .filter(([_, value]) => typeof value !== 'undefined') - .map(([key, value]) => { - if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') { - return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`; - } - if (value === null) { - return `${encodeURIComponent(key)}=`; - } - throw new OpenAIError( - `Cannot stringify type ${typeof value}; Expected string, number, boolean, or null. If you need to pass nested query parameters, you can manually encode them, e.g. { query: { 'foo[key1]': value1, 'foo[key2]': value2 } }, and please open a GitHub issue requesting better support for your use case.`, - ); - }) - .join('&'); - } - - async fetchWithTimeout( - url: RequestInfo, - init: RequestInit | undefined, - ms: number, - controller: AbortController, - ): Promise { - const { signal, ...options } = init || {}; - if (signal) signal.addEventListener('abort', () => controller.abort()); - - const timeout = setTimeout(() => controller.abort(), ms); - - return ( - // use undefined this binding; fetch errors if bound to something else in browser/cloudflare - this.fetch.call(undefined, url, { signal: controller.signal as any, ...options }).finally(() => { - clearTimeout(timeout); - }) - ); - } - - private shouldRetry(response: Response): boolean { - // Note this is not a standard header. - const shouldRetryHeader = response.headers.get('x-should-retry'); - - // If the server explicitly says whether or not to retry, obey. - if (shouldRetryHeader === 'true') return true; - if (shouldRetryHeader === 'false') return false; - - // Retry on request timeouts. - if (response.status === 408) return true; - - // Retry on lock timeouts. - if (response.status === 409) return true; - - // Retry on rate limits. - if (response.status === 429) return true; - - // Retry internal errors. - if (response.status >= 500) return true; - - return false; - } - - private async retryRequest( - options: FinalRequestOptions, - retriesRemaining: number, - responseHeaders?: Headers | undefined, - ): Promise { - let timeoutMillis: number | undefined; - - // Note the `retry-after-ms` header may not be standard, but is a good idea and we'd like proactive support for it. - const retryAfterMillisHeader = responseHeaders?.['retry-after-ms']; - if (retryAfterMillisHeader) { - const timeoutMs = parseFloat(retryAfterMillisHeader); - if (!Number.isNaN(timeoutMs)) { - timeoutMillis = timeoutMs; - } - } - - // About the Retry-After header: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After - const retryAfterHeader = responseHeaders?.['retry-after']; - if (retryAfterHeader && !timeoutMillis) { - const timeoutSeconds = parseFloat(retryAfterHeader); - if (!Number.isNaN(timeoutSeconds)) { - timeoutMillis = timeoutSeconds * 1000; - } else { - timeoutMillis = Date.parse(retryAfterHeader) - Date.now(); - } - } - - // If the API asks us to wait a certain amount of time (and it's a reasonable amount), - // just do what it says, but otherwise calculate a default - if (!(timeoutMillis && 0 <= timeoutMillis && timeoutMillis < 60 * 1000)) { - const maxRetries = options.maxRetries ?? this.maxRetries; - timeoutMillis = this.calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries); - } - await sleep(timeoutMillis); - - return this.makeRequest(options, retriesRemaining - 1); - } - - private calculateDefaultRetryTimeoutMillis(retriesRemaining: number, maxRetries: number): number { - const initialRetryDelay = 0.5; - const maxRetryDelay = 8.0; - - const numRetries = maxRetries - retriesRemaining; - - // Apply exponential backoff, but not more than the max. - const sleepSeconds = Math.min(initialRetryDelay * Math.pow(2, numRetries), maxRetryDelay); - - // Apply some jitter, take up to at most 25 percent of the retry time. - const jitter = 1 - Math.random() * 0.25; - - return sleepSeconds * jitter * 1000; - } - - private getUserAgent(): string { - return `${this.constructor.name}/JS ${VERSION}`; - } -} - -export type PageInfo = { url: URL } | { params: Record | null }; - -export abstract class AbstractPage implements AsyncIterable { - #client: APIClient; - protected options: FinalRequestOptions; - - protected response: Response; - protected body: unknown; - - constructor(client: APIClient, response: Response, body: unknown, options: FinalRequestOptions) { - this.#client = client; - this.options = options; - this.response = response; - this.body = body; - } - - /** - * @deprecated Use nextPageInfo instead - */ - abstract nextPageParams(): Partial> | null; - abstract nextPageInfo(): PageInfo | null; - - abstract getPaginatedItems(): Item[]; - - hasNextPage(): boolean { - const items = this.getPaginatedItems(); - if (!items.length) return false; - return this.nextPageInfo() != null; - } - - async getNextPage(): Promise { - const nextInfo = this.nextPageInfo(); - if (!nextInfo) { - throw new OpenAIError( - 'No next page expected; please check `.hasNextPage()` before calling `.getNextPage()`.', - ); - } - const nextOptions = { ...this.options }; - if ('params' in nextInfo && typeof nextOptions.query === 'object') { - nextOptions.query = { ...nextOptions.query, ...nextInfo.params }; - } else if ('url' in nextInfo) { - const params = [...Object.entries(nextOptions.query || {}), ...nextInfo.url.searchParams.entries()]; - for (const [key, value] of params) { - nextInfo.url.searchParams.set(key, value as any); - } - nextOptions.query = undefined; - nextOptions.path = nextInfo.url.toString(); - } - return await this.#client.requestAPIList(this.constructor as any, nextOptions); - } - - async *iterPages(): AsyncGenerator { - // eslint-disable-next-line @typescript-eslint/no-this-alias - let page: this = this; - yield page; - while (page.hasNextPage()) { - page = await page.getNextPage(); - yield page; - } - } - - async *[Symbol.asyncIterator](): AsyncGenerator { - for await (const page of this.iterPages()) { - for (const item of page.getPaginatedItems()) { - yield item; - } - } - } -} - -/** - * This subclass of Promise will resolve to an instantiated Page once the request completes. - * - * It also implements AsyncIterable to allow auto-paginating iteration on an unawaited list call, eg: - * - * for await (const item of client.items.list()) { - * console.log(item) - * } - */ -export class PagePromise< - PageClass extends AbstractPage, - Item = ReturnType[number], - > - extends APIPromise - implements AsyncIterable -{ - constructor( - client: APIClient, - request: Promise, - Page: new (...args: ConstructorParameters) => PageClass, - ) { - super( - request, - async (props) => - new Page( - client, - props.response, - await defaultParseResponse(props), - props.options, - ) as WithRequestID, - ); - } - - /** - * Allow auto-paginating iteration on an unawaited list call, eg: - * - * for await (const item of client.items.list()) { - * console.log(item) - * } - */ - async *[Symbol.asyncIterator](): AsyncGenerator { - const page = await this; - for await (const item of page) { - yield item; - } - } -} - -export const createResponseHeaders = ( - headers: Awaited>['headers'], -): Record => { - return new Proxy( - Object.fromEntries( - // @ts-ignore - headers.entries(), - ), - { - get(target, name) { - const key = name.toString(); - return target[key.toLowerCase()] || target[key]; - }, - }, - ); -}; - -type HTTPMethod = 'get' | 'post' | 'put' | 'patch' | 'delete'; - -export type RequestClient = { fetch: Fetch }; -export type Headers = Record; -export type DefaultQuery = Record; -export type KeysEnum = { [P in keyof Required]: true }; - -export type RequestOptions< - Req = unknown | Record | Readable | BlobLike | ArrayBufferView | ArrayBuffer, -> = { - method?: HTTPMethod; - path?: string; - query?: Req | undefined; - body?: Req | null | undefined; - headers?: Headers | undefined; - - maxRetries?: number; - stream?: boolean | undefined; - timeout?: number; - httpAgent?: Agent; - signal?: AbortSignal | undefined | null; - idempotencyKey?: string; - - __binaryRequest?: boolean | undefined; - __binaryResponse?: boolean | undefined; - __streamClass?: typeof Stream; -}; - -// This is required so that we can determine if a given object matches the RequestOptions -// type at runtime. While this requires duplication, it is enforced by the TypeScript -// compiler such that any missing / extraneous keys will cause an error. -const requestOptionsKeys: KeysEnum = { - method: true, - path: true, - query: true, - body: true, - headers: true, - - maxRetries: true, - stream: true, - timeout: true, - httpAgent: true, - signal: true, - idempotencyKey: true, - - __binaryRequest: true, - __binaryResponse: true, - __streamClass: true, -}; - -export const isRequestOptions = (obj: unknown): obj is RequestOptions => { - return ( - typeof obj === 'object' && - obj !== null && - !isEmptyObj(obj) && - Object.keys(obj).every((k) => hasOwn(requestOptionsKeys, k)) - ); -}; - -export type FinalRequestOptions | Readable | DataView> = - RequestOptions & { - method: HTTPMethod; - path: string; - }; - -declare const Deno: any; -declare const EdgeRuntime: any; -type Arch = 'x32' | 'x64' | 'arm' | 'arm64' | `other:${string}` | 'unknown'; -type PlatformName = - | 'MacOS' - | 'Linux' - | 'Windows' - | 'FreeBSD' - | 'OpenBSD' - | 'iOS' - | 'Android' - | `Other:${string}` - | 'Unknown'; -type Browser = 'ie' | 'edge' | 'chrome' | 'firefox' | 'safari'; -type PlatformProperties = { - 'X-Stainless-Lang': 'js'; - 'X-Stainless-Package-Version': string; - 'X-Stainless-OS': PlatformName; - 'X-Stainless-Arch': Arch; - 'X-Stainless-Runtime': 'node' | 'deno' | 'edge' | `browser:${Browser}` | 'unknown'; - 'X-Stainless-Runtime-Version': string; -}; -const getPlatformProperties = (): PlatformProperties => { - if (typeof Deno !== 'undefined' && Deno.build != null) { - return { - 'X-Stainless-Lang': 'js', - 'X-Stainless-Package-Version': VERSION, - 'X-Stainless-OS': normalizePlatform(Deno.build.os), - 'X-Stainless-Arch': normalizeArch(Deno.build.arch), - 'X-Stainless-Runtime': 'deno', - 'X-Stainless-Runtime-Version': - typeof Deno.version === 'string' ? Deno.version : Deno.version?.deno ?? 'unknown', - }; - } - if (typeof EdgeRuntime !== 'undefined') { - return { - 'X-Stainless-Lang': 'js', - 'X-Stainless-Package-Version': VERSION, - 'X-Stainless-OS': 'Unknown', - 'X-Stainless-Arch': `other:${EdgeRuntime}`, - 'X-Stainless-Runtime': 'edge', - 'X-Stainless-Runtime-Version': process.version, - }; - } - // Check if Node.js - if (Object.prototype.toString.call(typeof process !== 'undefined' ? process : 0) === '[object process]') { - return { - 'X-Stainless-Lang': 'js', - 'X-Stainless-Package-Version': VERSION, - 'X-Stainless-OS': normalizePlatform(process.platform), - 'X-Stainless-Arch': normalizeArch(process.arch), - 'X-Stainless-Runtime': 'node', - 'X-Stainless-Runtime-Version': process.version, - }; - } - - const browserInfo = getBrowserInfo(); - if (browserInfo) { - return { - 'X-Stainless-Lang': 'js', - 'X-Stainless-Package-Version': VERSION, - 'X-Stainless-OS': 'Unknown', - 'X-Stainless-Arch': 'unknown', - 'X-Stainless-Runtime': `browser:${browserInfo.browser}`, - 'X-Stainless-Runtime-Version': browserInfo.version, - }; - } - - // TODO add support for Cloudflare workers, etc. - return { - 'X-Stainless-Lang': 'js', - 'X-Stainless-Package-Version': VERSION, - 'X-Stainless-OS': 'Unknown', - 'X-Stainless-Arch': 'unknown', - 'X-Stainless-Runtime': 'unknown', - 'X-Stainless-Runtime-Version': 'unknown', - }; -}; - -type BrowserInfo = { - browser: Browser; - version: string; -}; - -declare const navigator: { userAgent: string } | undefined; - -// Note: modified from https://github.com/JS-DevTools/host-environment/blob/b1ab79ecde37db5d6e163c050e54fe7d287d7c92/src/isomorphic.browser.ts -function getBrowserInfo(): BrowserInfo | null { - if (typeof navigator === 'undefined' || !navigator) { - return null; - } - - // NOTE: The order matters here! - const browserPatterns = [ - { key: 'edge' as const, pattern: /Edge(?:\W+(\d+)\.(\d+)(?:\.(\d+))?)?/ }, - { key: 'ie' as const, pattern: /MSIE(?:\W+(\d+)\.(\d+)(?:\.(\d+))?)?/ }, - { key: 'ie' as const, pattern: /Trident(?:.*rv\:(\d+)\.(\d+)(?:\.(\d+))?)?/ }, - { key: 'chrome' as const, pattern: /Chrome(?:\W+(\d+)\.(\d+)(?:\.(\d+))?)?/ }, - { key: 'firefox' as const, pattern: /Firefox(?:\W+(\d+)\.(\d+)(?:\.(\d+))?)?/ }, - { key: 'safari' as const, pattern: /(?:Version\W+(\d+)\.(\d+)(?:\.(\d+))?)?(?:\W+Mobile\S*)?\W+Safari/ }, - ]; - - // Find the FIRST matching browser - for (const { key, pattern } of browserPatterns) { - const match = pattern.exec(navigator.userAgent); - if (match) { - const major = match[1] || 0; - const minor = match[2] || 0; - const patch = match[3] || 0; - - return { browser: key, version: `${major}.${minor}.${patch}` }; - } - } - - return null; -} - -const normalizeArch = (arch: string): Arch => { - // Node docs: - // - https://nodejs.org/api/process.html#processarch - // Deno docs: - // - https://doc.deno.land/deno/stable/~/Deno.build - if (arch === 'x32') return 'x32'; - if (arch === 'x86_64' || arch === 'x64') return 'x64'; - if (arch === 'arm') return 'arm'; - if (arch === 'aarch64' || arch === 'arm64') return 'arm64'; - if (arch) return `other:${arch}`; - return 'unknown'; -}; - -const normalizePlatform = (platform: string): PlatformName => { - // Node platforms: - // - https://nodejs.org/api/process.html#processplatform - // Deno platforms: - // - https://doc.deno.land/deno/stable/~/Deno.build - // - https://github.com/denoland/deno/issues/14799 - - platform = platform.toLowerCase(); - - // NOTE: this iOS check is untested and may not work - // Node does not work natively on IOS, there is a fork at - // https://github.com/nodejs-mobile/nodejs-mobile - // however it is unknown at the time of writing how to detect if it is running - if (platform.includes('ios')) return 'iOS'; - if (platform === 'android') return 'Android'; - if (platform === 'darwin') return 'MacOS'; - if (platform === 'win32') return 'Windows'; - if (platform === 'freebsd') return 'FreeBSD'; - if (platform === 'openbsd') return 'OpenBSD'; - if (platform === 'linux') return 'Linux'; - if (platform) return `Other:${platform}`; - return 'Unknown'; -}; - -let _platformHeaders: PlatformProperties; -const getPlatformHeaders = () => { - return (_platformHeaders ??= getPlatformProperties()); -}; - -export const safeJSON = (text: string) => { - try { - return JSON.parse(text); - } catch (err) { - return undefined; - } -}; - -// https://url.spec.whatwg.org/#url-scheme-string -const startsWithSchemeRegexp = /^[a-z][a-z0-9+.-]*:/i; -const isAbsoluteURL = (url: string): boolean => { - return startsWithSchemeRegexp.test(url); -}; - -export const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); - -const validatePositiveInteger = (name: string, n: unknown): number => { - if (typeof n !== 'number' || !Number.isInteger(n)) { - throw new OpenAIError(`${name} must be an integer`); - } - if (n < 0) { - throw new OpenAIError(`${name} must be a positive integer`); - } - return n; -}; - -export const castToError = (err: any): Error => { - if (err instanceof Error) return err; - if (typeof err === 'object' && err !== null) { - try { - return new Error(JSON.stringify(err)); - } catch {} - } - return new Error(err); -}; - -export const ensurePresent = (value: T | null | undefined): T => { - if (value == null) throw new OpenAIError(`Expected a value to be given but received ${value} instead.`); - return value; -}; - -/** - * Read an environment variable. - * - * Trims beginning and trailing whitespace. - * - * Will return undefined if the environment variable doesn't exist or cannot be accessed. - */ -export const readEnv = (env: string): string | undefined => { - if (typeof process !== 'undefined') { - return process.env?.[env]?.trim() ?? undefined; - } - if (typeof Deno !== 'undefined') { - return Deno.env?.get?.(env)?.trim(); - } - return undefined; -}; - -export const coerceInteger = (value: unknown): number => { - if (typeof value === 'number') return Math.round(value); - if (typeof value === 'string') return parseInt(value, 10); - - throw new OpenAIError(`Could not coerce ${value} (type: ${typeof value}) into a number`); -}; - -export const coerceFloat = (value: unknown): number => { - if (typeof value === 'number') return value; - if (typeof value === 'string') return parseFloat(value); - - throw new OpenAIError(`Could not coerce ${value} (type: ${typeof value}) into a number`); -}; - -export const coerceBoolean = (value: unknown): boolean => { - if (typeof value === 'boolean') return value; - if (typeof value === 'string') return value === 'true'; - return Boolean(value); -}; - -export const maybeCoerceInteger = (value: unknown): number | undefined => { - if (value === undefined) { - return undefined; - } - return coerceInteger(value); -}; - -export const maybeCoerceFloat = (value: unknown): number | undefined => { - if (value === undefined) { - return undefined; - } - return coerceFloat(value); -}; - -export const maybeCoerceBoolean = (value: unknown): boolean | undefined => { - if (value === undefined) { - return undefined; - } - return coerceBoolean(value); -}; - -// https://stackoverflow.com/a/34491287 -export function isEmptyObj(obj: Object | null | undefined): boolean { - if (!obj) return true; - for (const _k in obj) return false; - return true; -} - -// https://eslint.org/docs/latest/rules/no-prototype-builtins -export function hasOwn(obj: Object, key: string): boolean { - return Object.prototype.hasOwnProperty.call(obj, key); -} - -/** - * Copies headers from "newHeaders" onto "targetHeaders", - * using lower-case for all properties, - * ignoring any keys with undefined values, - * and deleting any keys with null values. - */ -function applyHeadersMut(targetHeaders: Headers, newHeaders: Headers): void { - for (const k in newHeaders) { - if (!hasOwn(newHeaders, k)) continue; - const lowerKey = k.toLowerCase(); - if (!lowerKey) continue; - - const val = newHeaders[k]; - - if (val === null) { - delete targetHeaders[lowerKey]; - } else if (val !== undefined) { - targetHeaders[lowerKey] = val; - } - } -} - -export function debug(action: string, ...args: any[]) { - if (typeof process !== 'undefined' && process?.env?.['DEBUG'] === 'true') { - console.log(`OpenAI:DEBUG:${action}`, ...args); - } -} - -/** - * https://stackoverflow.com/a/2117523 - */ -const uuid4 = () => { - return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => { - const r = (Math.random() * 16) | 0; - const v = c === 'x' ? r : (r & 0x3) | 0x8; - return v.toString(16); - }); -}; - -export const isRunningInBrowser = () => { - return ( - // @ts-ignore - typeof window !== 'undefined' && - // @ts-ignore - typeof window.document !== 'undefined' && - // @ts-ignore - typeof navigator !== 'undefined' - ); -}; - -export interface HeadersProtocol { - get: (header: string) => string | null | undefined; -} -export type HeadersLike = Record | HeadersProtocol; - -export const isHeadersProtocol = (headers: any): headers is HeadersProtocol => { - return typeof headers?.get === 'function'; -}; - -export const getRequiredHeader = (headers: HeadersLike | Headers, header: string): string => { - const foundHeader = getHeader(headers, header); - if (foundHeader === undefined) { - throw new Error(`Could not find ${header} header`); - } - return foundHeader; -}; - -export const getHeader = (headers: HeadersLike | Headers, header: string): string | undefined => { - const lowerCasedHeader = header.toLowerCase(); - if (isHeadersProtocol(headers)) { - // to deal with the case where the header looks like Stainless-Event-Id - const intercapsHeader = - header[0]?.toUpperCase() + - header.substring(1).replace(/([^\w])(\w)/g, (_m, g1, g2) => g1 + g2.toUpperCase()); - for (const key of [header, lowerCasedHeader, header.toUpperCase(), intercapsHeader]) { - const value = headers.get(key); - if (value) { - return value; - } - } - } - - for (const [key, value] of Object.entries(headers)) { - if (key.toLowerCase() === lowerCasedHeader) { - if (Array.isArray(value)) { - if (value.length <= 1) return value[0]; - console.warn(`Received ${value.length} entries for the ${header} header, using the first entry.`); - return value[0]; - } - return value; - } - } - - return undefined; -}; - -/** - * Encodes a string to Base64 format. - */ -export const toBase64 = (str: string | null | undefined): string => { - if (!str) return ''; - if (typeof Buffer !== 'undefined') { - return Buffer.from(str).toString('base64'); - } - - if (typeof btoa !== 'undefined') { - return btoa(str); - } - - throw new OpenAIError('Cannot generate b64 string; Expected `Buffer` or `btoa` to be defined'); -}; - -export function isObj(obj: unknown): obj is Record { - return obj != null && typeof obj === 'object' && !Array.isArray(obj); -} diff --git a/src/error.ts b/src/error.ts index f3dc57610..74251d51f 100644 --- a/src/error.ts +++ b/src/error.ts @@ -1,6 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { castToError, Headers } from './core'; +import { castToError } from './internal/errors'; export class OpenAIError extends Error {} @@ -20,13 +20,13 @@ export class APIError< readonly param: string | null | undefined; readonly type: string | undefined; - readonly request_id: string | null | undefined; + readonly requestID: string | null | undefined; constructor(status: TStatus, error: TError, message: string | undefined, headers: THeaders) { super(`${APIError.makeMessage(status, error, message)}`); this.status = status; this.headers = headers; - this.request_id = headers?.['x-request-id']; + this.requestID = headers?.get('x-request-id'); this.error = error; const data = error as Record; diff --git a/src/index.ts b/src/index.ts index 2320850fb..9fb1eeb03 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,654 +1,11 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { type Agent, type RequestInit } from './_shims/index'; -import * as qs from './internal/qs'; -import * as Core from './core'; -import * as Errors from './error'; -import * as Pagination from './pagination'; -import { type CursorPageParams, CursorPageResponse, PageResponse } from './pagination'; -import * as Uploads from './uploads'; -import * as API from './resources/index'; -import { - Batch, - BatchCreateParams, - BatchError, - BatchListParams, - BatchRequestCounts, - Batches, - BatchesPage, -} from './resources/batches'; -import { - Completion, - CompletionChoice, - CompletionCreateParams, - CompletionCreateParamsNonStreaming, - CompletionCreateParamsStreaming, - CompletionUsage, - Completions, -} from './resources/completions'; -import { - CreateEmbeddingResponse, - Embedding, - EmbeddingCreateParams, - EmbeddingModel, - Embeddings, -} from './resources/embeddings'; -import { - FileContent, - FileCreateParams, - FileDeleted, - FileListParams, - FileObject, - FileObjectsPage, - FilePurpose, - Files, -} from './resources/files'; -import { - Image, - ImageCreateVariationParams, - ImageEditParams, - ImageGenerateParams, - ImageModel, - Images, - ImagesResponse, -} from './resources/images'; -import { Model, ModelDeleted, Models, ModelsPage } from './resources/models'; -import { - Moderation, - ModerationCreateParams, - ModerationCreateResponse, - ModerationImageURLInput, - ModerationModel, - ModerationMultiModalInput, - ModerationTextInput, - Moderations, -} from './resources/moderations'; -import { Audio, AudioModel, AudioResponseFormat } from './resources/audio/audio'; -import { Beta } from './resources/beta/beta'; -import { Chat, ChatModel } from './resources/chat/chat'; -import { - ChatCompletion, - ChatCompletionAssistantMessageParam, - ChatCompletionAudio, - ChatCompletionAudioParam, - ChatCompletionChunk, - ChatCompletionContentPart, - ChatCompletionContentPartImage, - ChatCompletionContentPartInputAudio, - ChatCompletionContentPartRefusal, - ChatCompletionContentPartText, - ChatCompletionCreateParams, - ChatCompletionCreateParamsNonStreaming, - ChatCompletionCreateParamsStreaming, - ChatCompletionDeveloperMessageParam, - ChatCompletionFunctionCallOption, - ChatCompletionFunctionMessageParam, - ChatCompletionMessage, - ChatCompletionMessageParam, - ChatCompletionMessageToolCall, - ChatCompletionModality, - ChatCompletionNamedToolChoice, - ChatCompletionPredictionContent, - ChatCompletionReasoningEffort, - ChatCompletionRole, - ChatCompletionStreamOptions, - ChatCompletionSystemMessageParam, - ChatCompletionTokenLogprob, - ChatCompletionTool, - ChatCompletionToolChoiceOption, - ChatCompletionToolMessageParam, - ChatCompletionUserMessageParam, -} from './resources/chat/completions'; -import { FineTuning } from './resources/fine-tuning/fine-tuning'; -import { - Upload, - UploadCompleteParams, - UploadCreateParams, - Uploads as UploadsAPIUploads, -} from './resources/uploads/uploads'; +export { OpenAI as default } from './client'; -export interface ClientOptions { - /** - * Defaults to process.env['OPENAI_API_KEY']. - */ - apiKey?: string | undefined; - - /** - * Defaults to process.env['OPENAI_ORG_ID']. - */ - organization?: string | null | undefined; - - /** - * Defaults to process.env['OPENAI_PROJECT_ID']. - */ - project?: string | null | undefined; - - /** - * Override the default base URL for the API, e.g., "https://api.example.com/v2/" - * - * Defaults to process.env['OPENAI_BASE_URL']. - */ - baseURL?: string | null | undefined; - - /** - * The maximum amount of time (in milliseconds) that the client should wait for a response - * from the server before timing out a single request. - * - * Note that request timeouts are retried by default, so in a worst-case scenario you may wait - * much longer than this timeout before the promise succeeds or fails. - */ - timeout?: number; - - /** - * An HTTP agent used to manage HTTP(S) connections. - * - * If not provided, an agent will be constructed by default in the Node.js environment, - * otherwise no agent is used. - */ - httpAgent?: Agent; - - /** - * Specify a custom `fetch` function implementation. - * - * If not provided, we use `node-fetch` on Node.js and otherwise expect that `fetch` is - * defined globally. - */ - fetch?: Core.Fetch | undefined; - - /** - * The maximum number of times that the client will retry a request in case of a - * temporary failure, like a network error or a 5XX error from the server. - * - * @default 2 - */ - maxRetries?: number; - - /** - * Default headers to include with every request to the API. - * - * These can be removed in individual requests by explicitly setting the - * header to `undefined` or `null` in request options. - */ - defaultHeaders?: Core.Headers; - - /** - * Default query parameters to include with every request to the API. - * - * These can be removed in individual requests by explicitly setting the - * param to `undefined` in request options. - */ - defaultQuery?: Core.DefaultQuery; - - /** - * By default, client-side use of this library is not allowed, as it risks exposing your secret API credentials to attackers. - * Only set this option to `true` if you understand the risks and have appropriate mitigations in place. - */ - dangerouslyAllowBrowser?: boolean; -} - -/** - * API Client for interfacing with the OpenAI API. - */ -export class OpenAI extends Core.APIClient { - apiKey: string; - organization: string | null; - project: string | null; - - private _options: ClientOptions; - - /** - * API Client for interfacing with the OpenAI API. - * - * @param {string | undefined} [opts.apiKey=process.env['OPENAI_API_KEY'] ?? undefined] - * @param {string | null | undefined} [opts.organization=process.env['OPENAI_ORG_ID'] ?? null] - * @param {string | null | undefined} [opts.project=process.env['OPENAI_PROJECT_ID'] ?? null] - * @param {string} [opts.baseURL=process.env['OPENAI_BASE_URL'] ?? https://api.openai.com/v1] - Override the default base URL for the API. - * @param {number} [opts.timeout=10 minutes] - The maximum amount of time (in milliseconds) the client will wait for a response before timing out. - * @param {number} [opts.httpAgent] - An HTTP agent used to manage HTTP(s) connections. - * @param {Core.Fetch} [opts.fetch] - Specify a custom `fetch` function implementation. - * @param {number} [opts.maxRetries=2] - The maximum number of times the client will retry a request. - * @param {Core.Headers} opts.defaultHeaders - Default headers to include with every request to the API. - * @param {Core.DefaultQuery} opts.defaultQuery - Default query parameters to include with every request to the API. - * @param {boolean} [opts.dangerouslyAllowBrowser=false] - By default, client-side use of this library is not allowed, as it risks exposing your secret API credentials to attackers. - */ - constructor({ - baseURL = Core.readEnv('OPENAI_BASE_URL'), - apiKey = Core.readEnv('OPENAI_API_KEY'), - organization = Core.readEnv('OPENAI_ORG_ID') ?? null, - project = Core.readEnv('OPENAI_PROJECT_ID') ?? null, - ...opts - }: ClientOptions = {}) { - if (apiKey === undefined) { - throw new Errors.OpenAIError( - "The OPENAI_API_KEY environment variable is missing or empty; either provide it, or instantiate the OpenAI client with an apiKey option, like new OpenAI({ apiKey: 'My API Key' }).", - ); - } - - const options: ClientOptions = { - apiKey, - organization, - project, - ...opts, - baseURL: baseURL || `https://api.openai.com/v1`, - }; - - if (!options.dangerouslyAllowBrowser && Core.isRunningInBrowser()) { - throw new Errors.OpenAIError( - "It looks like you're running in a browser-like environment.\n\nThis is disabled by default, as it risks exposing your secret API credentials to attackers.\nIf you understand the risks and have appropriate mitigations in place,\nyou can set the `dangerouslyAllowBrowser` option to `true`, e.g.,\n\nnew OpenAI({ apiKey, dangerouslyAllowBrowser: true });\n\nhttps://help.openai.com/en/articles/5112595-best-practices-for-api-key-safety\n", - ); - } - - super({ - baseURL: options.baseURL!, - timeout: options.timeout ?? 600000 /* 10 minutes */, - httpAgent: options.httpAgent, - maxRetries: options.maxRetries, - fetch: options.fetch, - }); - - this._options = options; - - this.apiKey = apiKey; - this.organization = organization; - this.project = project; - } - - completions: API.Completions = new API.Completions(this); - chat: API.Chat = new API.Chat(this); - embeddings: API.Embeddings = new API.Embeddings(this); - files: API.Files = new API.Files(this); - images: API.Images = new API.Images(this); - audio: API.Audio = new API.Audio(this); - moderations: API.Moderations = new API.Moderations(this); - models: API.Models = new API.Models(this); - fineTuning: API.FineTuning = new API.FineTuning(this); - beta: API.Beta = new API.Beta(this); - batches: API.Batches = new API.Batches(this); - uploads: API.Uploads = new API.Uploads(this); - - protected override defaultQuery(): Core.DefaultQuery | undefined { - return this._options.defaultQuery; - } - - protected override defaultHeaders(opts: Core.FinalRequestOptions): Core.Headers { - return { - ...super.defaultHeaders(opts), - 'OpenAI-Organization': this.organization, - 'OpenAI-Project': this.project, - ...this._options.defaultHeaders, - }; - } - - protected override authHeaders(opts: Core.FinalRequestOptions): Core.Headers { - return { Authorization: `Bearer ${this.apiKey}` }; - } - - protected override stringifyQuery(query: Record): string { - return qs.stringify(query, { arrayFormat: 'brackets' }); - } - - static OpenAI = this; - static DEFAULT_TIMEOUT = 600000; // 10 minutes - - static OpenAIError = Errors.OpenAIError; - static APIError = Errors.APIError; - static APIConnectionError = Errors.APIConnectionError; - static APIConnectionTimeoutError = Errors.APIConnectionTimeoutError; - static APIUserAbortError = Errors.APIUserAbortError; - static NotFoundError = Errors.NotFoundError; - static ConflictError = Errors.ConflictError; - static RateLimitError = Errors.RateLimitError; - static BadRequestError = Errors.BadRequestError; - static AuthenticationError = Errors.AuthenticationError; - static InternalServerError = Errors.InternalServerError; - static PermissionDeniedError = Errors.PermissionDeniedError; - static UnprocessableEntityError = Errors.UnprocessableEntityError; - - static toFile = Uploads.toFile; - static fileFromPath = Uploads.fileFromPath; -} - -OpenAI.Completions = Completions; -OpenAI.Chat = Chat; -OpenAI.Embeddings = Embeddings; -OpenAI.Files = Files; -OpenAI.FileObjectsPage = FileObjectsPage; -OpenAI.Images = Images; -OpenAI.Audio = Audio; -OpenAI.Moderations = Moderations; -OpenAI.Models = Models; -OpenAI.ModelsPage = ModelsPage; -OpenAI.FineTuning = FineTuning; -OpenAI.Beta = Beta; -OpenAI.Batches = Batches; -OpenAI.BatchesPage = BatchesPage; -OpenAI.Uploads = UploadsAPIUploads; -export declare namespace OpenAI { - export type RequestOptions = Core.RequestOptions; - - export import Page = Pagination.Page; - export { type PageResponse as PageResponse }; - - export import CursorPage = Pagination.CursorPage; - export { type CursorPageParams as CursorPageParams, type CursorPageResponse as CursorPageResponse }; - - export { - Completions as Completions, - type Completion as Completion, - type CompletionChoice as CompletionChoice, - type CompletionUsage as CompletionUsage, - type CompletionCreateParams as CompletionCreateParams, - type CompletionCreateParamsNonStreaming as CompletionCreateParamsNonStreaming, - type CompletionCreateParamsStreaming as CompletionCreateParamsStreaming, - }; - - export { - Chat as Chat, - type ChatModel as ChatModel, - type ChatCompletion as ChatCompletion, - type ChatCompletionAssistantMessageParam as ChatCompletionAssistantMessageParam, - type ChatCompletionAudio as ChatCompletionAudio, - type ChatCompletionAudioParam as ChatCompletionAudioParam, - type ChatCompletionChunk as ChatCompletionChunk, - type ChatCompletionContentPart as ChatCompletionContentPart, - type ChatCompletionContentPartImage as ChatCompletionContentPartImage, - type ChatCompletionContentPartInputAudio as ChatCompletionContentPartInputAudio, - type ChatCompletionContentPartRefusal as ChatCompletionContentPartRefusal, - type ChatCompletionContentPartText as ChatCompletionContentPartText, - type ChatCompletionDeveloperMessageParam as ChatCompletionDeveloperMessageParam, - type ChatCompletionFunctionCallOption as ChatCompletionFunctionCallOption, - type ChatCompletionFunctionMessageParam as ChatCompletionFunctionMessageParam, - type ChatCompletionMessage as ChatCompletionMessage, - type ChatCompletionMessageParam as ChatCompletionMessageParam, - type ChatCompletionMessageToolCall as ChatCompletionMessageToolCall, - type ChatCompletionModality as ChatCompletionModality, - type ChatCompletionNamedToolChoice as ChatCompletionNamedToolChoice, - type ChatCompletionPredictionContent as ChatCompletionPredictionContent, - type ChatCompletionReasoningEffort as ChatCompletionReasoningEffort, - type ChatCompletionRole as ChatCompletionRole, - type ChatCompletionStreamOptions as ChatCompletionStreamOptions, - type ChatCompletionSystemMessageParam as ChatCompletionSystemMessageParam, - type ChatCompletionTokenLogprob as ChatCompletionTokenLogprob, - type ChatCompletionTool as ChatCompletionTool, - type ChatCompletionToolChoiceOption as ChatCompletionToolChoiceOption, - type ChatCompletionToolMessageParam as ChatCompletionToolMessageParam, - type ChatCompletionUserMessageParam as ChatCompletionUserMessageParam, - type ChatCompletionCreateParams as ChatCompletionCreateParams, - type ChatCompletionCreateParamsNonStreaming as ChatCompletionCreateParamsNonStreaming, - type ChatCompletionCreateParamsStreaming as ChatCompletionCreateParamsStreaming, - }; - - export { - Embeddings as Embeddings, - type CreateEmbeddingResponse as CreateEmbeddingResponse, - type Embedding as Embedding, - type EmbeddingModel as EmbeddingModel, - type EmbeddingCreateParams as EmbeddingCreateParams, - }; - - export { - Files as Files, - type FileContent as FileContent, - type FileDeleted as FileDeleted, - type FileObject as FileObject, - type FilePurpose as FilePurpose, - FileObjectsPage as FileObjectsPage, - type FileCreateParams as FileCreateParams, - type FileListParams as FileListParams, - }; - - export { - Images as Images, - type Image as Image, - type ImageModel as ImageModel, - type ImagesResponse as ImagesResponse, - type ImageCreateVariationParams as ImageCreateVariationParams, - type ImageEditParams as ImageEditParams, - type ImageGenerateParams as ImageGenerateParams, - }; - - export { Audio as Audio, type AudioModel as AudioModel, type AudioResponseFormat as AudioResponseFormat }; - - export { - Moderations as Moderations, - type Moderation as Moderation, - type ModerationImageURLInput as ModerationImageURLInput, - type ModerationModel as ModerationModel, - type ModerationMultiModalInput as ModerationMultiModalInput, - type ModerationTextInput as ModerationTextInput, - type ModerationCreateResponse as ModerationCreateResponse, - type ModerationCreateParams as ModerationCreateParams, - }; - - export { - Models as Models, - type Model as Model, - type ModelDeleted as ModelDeleted, - ModelsPage as ModelsPage, - }; - - export { FineTuning as FineTuning }; - - export { Beta as Beta }; - - export { - Batches as Batches, - type Batch as Batch, - type BatchError as BatchError, - type BatchRequestCounts as BatchRequestCounts, - BatchesPage as BatchesPage, - type BatchCreateParams as BatchCreateParams, - type BatchListParams as BatchListParams, - }; - - export { - UploadsAPIUploads as Uploads, - type Upload as Upload, - type UploadCreateParams as UploadCreateParams, - type UploadCompleteParams as UploadCompleteParams, - }; - - export type ErrorObject = API.ErrorObject; - export type FunctionDefinition = API.FunctionDefinition; - export type FunctionParameters = API.FunctionParameters; - export type ResponseFormatJSONObject = API.ResponseFormatJSONObject; - export type ResponseFormatJSONSchema = API.ResponseFormatJSONSchema; - export type ResponseFormatText = API.ResponseFormatText; -} - -// ---------------------- Azure ---------------------- - -/** API Client for interfacing with the Azure OpenAI API. */ -export interface AzureClientOptions extends ClientOptions { - /** - * Defaults to process.env['OPENAI_API_VERSION']. - */ - apiVersion?: string | undefined; - - /** - * Your Azure endpoint, including the resource, e.g. `https://example-resource.azure.openai.com/` - */ - endpoint?: string | undefined; - - /** - * A model deployment, if given, sets the base client URL to include `/deployments/{deployment}`. - * Note: this means you won't be able to use non-deployment endpoints. Not supported with Assistants APIs. - */ - deployment?: string | undefined; - - /** - * Defaults to process.env['AZURE_OPENAI_API_KEY']. - */ - apiKey?: string | undefined; - - /** - * A function that returns an access token for Microsoft Entra (formerly known as Azure Active Directory), - * which will be invoked on every request. - */ - azureADTokenProvider?: (() => Promise) | undefined; -} - -/** API Client for interfacing with the Azure OpenAI API. */ -export class AzureOpenAI extends OpenAI { - private _azureADTokenProvider: (() => Promise) | undefined; - private _deployment: string | undefined; - apiVersion: string = ''; - /** - * API Client for interfacing with the Azure OpenAI API. - * - * @param {string | undefined} [opts.apiVersion=process.env['OPENAI_API_VERSION'] ?? undefined] - * @param {string | undefined} [opts.endpoint=process.env['AZURE_OPENAI_ENDPOINT'] ?? undefined] - Your Azure endpoint, including the resource, e.g. `https://example-resource.azure.openai.com/` - * @param {string | undefined} [opts.apiKey=process.env['AZURE_OPENAI_API_KEY'] ?? undefined] - * @param {string | undefined} opts.deployment - A model deployment, if given, sets the base client URL to include `/deployments/{deployment}`. - * @param {string | null | undefined} [opts.organization=process.env['OPENAI_ORG_ID'] ?? null] - * @param {string} [opts.baseURL=process.env['OPENAI_BASE_URL']] - Sets the base URL for the API, e.g. `https://example-resource.azure.openai.com/openai/`. - * @param {number} [opts.timeout=10 minutes] - The maximum amount of time (in milliseconds) the client will wait for a response before timing out. - * @param {number} [opts.httpAgent] - An HTTP agent used to manage HTTP(s) connections. - * @param {Core.Fetch} [opts.fetch] - Specify a custom `fetch` function implementation. - * @param {number} [opts.maxRetries=2] - The maximum number of times the client will retry a request. - * @param {Core.Headers} opts.defaultHeaders - Default headers to include with every request to the API. - * @param {Core.DefaultQuery} opts.defaultQuery - Default query parameters to include with every request to the API. - * @param {boolean} [opts.dangerouslyAllowBrowser=false] - By default, client-side use of this library is not allowed, as it risks exposing your secret API credentials to attackers. - */ - constructor({ - baseURL = Core.readEnv('OPENAI_BASE_URL'), - apiKey = Core.readEnv('AZURE_OPENAI_API_KEY'), - apiVersion = Core.readEnv('OPENAI_API_VERSION'), - endpoint, - deployment, - azureADTokenProvider, - dangerouslyAllowBrowser, - ...opts - }: AzureClientOptions = {}) { - if (!apiVersion) { - throw new Errors.OpenAIError( - "The OPENAI_API_VERSION environment variable is missing or empty; either provide it, or instantiate the AzureOpenAI client with an apiVersion option, like new AzureOpenAI({ apiVersion: 'My API Version' }).", - ); - } - - if (typeof azureADTokenProvider === 'function') { - dangerouslyAllowBrowser = true; - } - - if (!azureADTokenProvider && !apiKey) { - throw new Errors.OpenAIError( - 'Missing credentials. Please pass one of `apiKey` and `azureADTokenProvider`, or set the `AZURE_OPENAI_API_KEY` environment variable.', - ); - } - - if (azureADTokenProvider && apiKey) { - throw new Errors.OpenAIError( - 'The `apiKey` and `azureADTokenProvider` arguments are mutually exclusive; only one can be passed at a time.', - ); - } - - // define a sentinel value to avoid any typing issues - apiKey ??= API_KEY_SENTINEL; - - opts.defaultQuery = { ...opts.defaultQuery, 'api-version': apiVersion }; - - if (!baseURL) { - if (!endpoint) { - endpoint = process.env['AZURE_OPENAI_ENDPOINT']; - } - - if (!endpoint) { - throw new Errors.OpenAIError( - 'Must provide one of the `baseURL` or `endpoint` arguments, or the `AZURE_OPENAI_ENDPOINT` environment variable', - ); - } - - baseURL = `${endpoint}/openai`; - } else { - if (endpoint) { - throw new Errors.OpenAIError('baseURL and endpoint are mutually exclusive'); - } - } - - super({ - apiKey, - baseURL, - ...opts, - ...(dangerouslyAllowBrowser !== undefined ? { dangerouslyAllowBrowser } : {}), - }); - - this._azureADTokenProvider = azureADTokenProvider; - this.apiVersion = apiVersion; - this._deployment = deployment; - } - - override buildRequest(options: Core.FinalRequestOptions): { - req: RequestInit; - url: string; - timeout: number; - } { - if (_deployments_endpoints.has(options.path) && options.method === 'post' && options.body !== undefined) { - if (!Core.isObj(options.body)) { - throw new Error('Expected request body to be an object'); - } - const model = this._deployment || options.body['model']; - if (model !== undefined && !this.baseURL.includes('/deployments')) { - options.path = `/deployments/${model}${options.path}`; - } - } - return super.buildRequest(options); - } - - private async _getAzureADToken(): Promise { - if (typeof this._azureADTokenProvider === 'function') { - const token = await this._azureADTokenProvider(); - if (!token || typeof token !== 'string') { - throw new Errors.OpenAIError( - `Expected 'azureADTokenProvider' argument to return a string but it returned ${token}`, - ); - } - return token; - } - return undefined; - } - - protected override authHeaders(opts: Core.FinalRequestOptions): Core.Headers { - return {}; - } - - protected override async prepareOptions(opts: Core.FinalRequestOptions): Promise { - /** - * The user should provide a bearer token provider if they want - * to use Azure AD authentication. The user shouldn't set the - * Authorization header manually because the header is overwritten - * with the Azure AD token if a bearer token provider is provided. - */ - if (opts.headers?.['api-key']) { - return super.prepareOptions(opts); - } - const token = await this._getAzureADToken(); - opts.headers ??= {}; - if (token) { - opts.headers['Authorization'] = `Bearer ${token}`; - } else if (this.apiKey !== API_KEY_SENTINEL) { - opts.headers['api-key'] = this.apiKey; - } else { - throw new Errors.OpenAIError('Unable to handle auth'); - } - return super.prepareOptions(opts); - } -} - -const _deployments_endpoints = new Set([ - '/completions', - '/chat/completions', - '/embeddings', - '/audio/transcriptions', - '/audio/translations', - '/audio/speech', - '/images/generations', -]); - -const API_KEY_SENTINEL = ''; - -// ---------------------- End Azure ---------------------- - -export { toFile, fileFromPath } from './uploads'; +export { type Uploadable, toFile } from './uploads'; +export { APIPromise } from './api-promise'; +export { OpenAI, type ClientOptions } from './client'; +export { PagePromise } from './pagination'; export { OpenAIError, APIError, @@ -665,4 +22,4 @@ export { UnprocessableEntityError, } from './error'; -export default OpenAI; +export { AzureOpenAI } from './azure'; diff --git a/src/internal/builtin-types.ts b/src/internal/builtin-types.ts new file mode 100644 index 000000000..b2e598a81 --- /dev/null +++ b/src/internal/builtin-types.ts @@ -0,0 +1,79 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export type Fetch = (input: string | URL | Request, init?: RequestInit) => Promise; + +/** + * An alias to the builtin `RequestInit` type so we can + * easily alias it in import statements if there are name clashes. + * + * https://developer.mozilla.org/docs/Web/API/RequestInit + */ +type _RequestInit = RequestInit; + +/** + * An alias to the builtin `Response` type so we can + * easily alias it in import statements if there are name clashes. + * + * https://developer.mozilla.org/docs/Web/API/Response + */ +type _Response = Response; + +/** + * The type for the first argument to `fetch`. + * + * https://developer.mozilla.org/docs/Web/API/Window/fetch#resource + */ +type _RequestInfo = Request | URL | string; + +/** + * The type for constructing `RequestInit` Headers. + * + * https://developer.mozilla.org/docs/Web/API/RequestInit#setting_headers + */ +type _HeadersInit = RequestInit['headers']; + +/** + * The type for constructing `RequestInit` body. + * + * https://developer.mozilla.org/docs/Web/API/RequestInit#body + */ +type _BodyInit = RequestInit['body']; + +export type { + _BodyInit as BodyInit, + _HeadersInit as HeadersInit, + _RequestInfo as RequestInfo, + _RequestInit as RequestInit, + _Response as Response, +}; + +/** + * A copy of the builtin `EndingType` type as it isn't fully supported in certain + * environments and attempting to reference the global version will error. + * + * https://github.com/microsoft/TypeScript/blob/49ad1a3917a0ea57f5ff248159256e12bb1cb705/src/lib/dom.generated.d.ts#L27941 + */ +type EndingType = 'native' | 'transparent'; + +/** + * A copy of the builtin `BlobPropertyBag` type as it isn't fully supported in certain + * environments and attempting to reference the global version will error. + * + * https://github.com/microsoft/TypeScript/blob/49ad1a3917a0ea57f5ff248159256e12bb1cb705/src/lib/dom.generated.d.ts#L154 + * https://developer.mozilla.org/en-US/docs/Web/API/Blob/Blob#options + */ +export interface BlobPropertyBag { + endings?: EndingType; + type?: string; +} + +/** + * A copy of the builtin `FilePropertyBag` type as it isn't fully supported in certain + * environments and attempting to reference the global version will error. + * + * https://github.com/microsoft/TypeScript/blob/49ad1a3917a0ea57f5ff248159256e12bb1cb705/src/lib/dom.generated.d.ts#L503 + * https://developer.mozilla.org/en-US/docs/Web/API/File/File#options + */ +export interface FilePropertyBag extends BlobPropertyBag { + lastModified?: number; +} diff --git a/src/internal/decoders/line.ts b/src/internal/decoders/line.ts index 1e0bbf390..335ad7e30 100644 --- a/src/internal/decoders/line.ts +++ b/src/internal/decoders/line.ts @@ -1,6 +1,6 @@ import { OpenAIError } from '../../error'; -type Bytes = string | ArrayBuffer | Uint8Array | Buffer | null | undefined; +export type Bytes = string | ArrayBuffer | Uint8Array | null | undefined; /** * A re-implementation of httpx's `LineDecoder` in Python that handles incrementally @@ -13,52 +13,62 @@ export class LineDecoder { static NEWLINE_CHARS = new Set(['\n', '\r']); static NEWLINE_REGEXP = /\r\n|[\n\r]/g; - buffer: string[]; - trailingCR: boolean; - textDecoder: any; // TextDecoder found in browsers; not typed to avoid pulling in either "dom" or "node" types. + buffer: Uint8Array; + #carriageReturnIndex: number | null; + textDecoder: + | undefined + | { + decode(buffer: Uint8Array | ArrayBuffer): string; + }; constructor() { - this.buffer = []; - this.trailingCR = false; + this.buffer = new Uint8Array(); + this.#carriageReturnIndex = null; } decode(chunk: Bytes): string[] { - let text = this.decodeText(chunk); - - if (this.trailingCR) { - text = '\r' + text; - this.trailingCR = false; - } - if (text.endsWith('\r')) { - this.trailingCR = true; - text = text.slice(0, -1); - } - - if (!text) { + if (chunk == null) { return []; } - const trailingNewline = LineDecoder.NEWLINE_CHARS.has(text[text.length - 1] || ''); - let lines = text.split(LineDecoder.NEWLINE_REGEXP); + const binaryChunk = + chunk instanceof ArrayBuffer ? new Uint8Array(chunk) + : typeof chunk === 'string' ? new TextEncoder().encode(chunk) + : chunk; + + let newData = new Uint8Array(this.buffer.length + binaryChunk.length); + newData.set(this.buffer); + newData.set(binaryChunk, this.buffer.length); + this.buffer = newData; + + const lines: string[] = []; + let patternIndex; + while ((patternIndex = findNewlineIndex(this.buffer, this.#carriageReturnIndex)) != null) { + if (patternIndex.carriage && this.#carriageReturnIndex == null) { + // skip until we either get a corresponding `\n`, a new `\r` or nothing + this.#carriageReturnIndex = patternIndex.index; + continue; + } - // if there is a trailing new line then the last entry will be an empty - // string which we don't care about - if (trailingNewline) { - lines.pop(); - } + // we got double \r or \rtext\n + if ( + this.#carriageReturnIndex != null && + (patternIndex.index !== this.#carriageReturnIndex + 1 || patternIndex.carriage) + ) { + lines.push(this.decodeText(this.buffer.slice(0, this.#carriageReturnIndex - 1))); + this.buffer = this.buffer.slice(this.#carriageReturnIndex); + this.#carriageReturnIndex = null; + continue; + } - if (lines.length === 1 && !trailingNewline) { - this.buffer.push(lines[0]!); - return []; - } + const endIndex = + this.#carriageReturnIndex !== null ? patternIndex.preceding - 1 : patternIndex.preceding; - if (this.buffer.length > 0) { - lines = [this.buffer.join('') + lines[0], ...lines.slice(1)]; - this.buffer = []; - } + const line = this.decodeText(this.buffer.slice(0, endIndex)); + lines.push(line); - if (!trailingNewline) { - this.buffer = [lines.pop() || '']; + this.buffer = this.buffer.slice(patternIndex.index); + this.#carriageReturnIndex = null; } return lines; @@ -69,12 +79,12 @@ export class LineDecoder { if (typeof bytes === 'string') return bytes; // Node: - if (typeof Buffer !== 'undefined') { - if (bytes instanceof Buffer) { + if (typeof (globalThis as any).Buffer !== 'undefined') { + if (bytes instanceof (globalThis as any).Buffer) { return bytes.toString(); } if (bytes instanceof Uint8Array) { - return Buffer.from(bytes).toString(); + return (globalThis as any).Buffer.from(bytes).toString(); } throw new OpenAIError( @@ -83,10 +93,10 @@ export class LineDecoder { } // Browser - if (typeof TextDecoder !== 'undefined') { + if (typeof (globalThis as any).TextDecoder !== 'undefined') { if (bytes instanceof Uint8Array || bytes instanceof ArrayBuffer) { - this.textDecoder ??= new TextDecoder('utf8'); - return this.textDecoder.decode(bytes); + this.textDecoder ??= new (globalThis as any).TextDecoder('utf8'); + return this.textDecoder!.decode(bytes); } throw new OpenAIError( @@ -102,13 +112,69 @@ export class LineDecoder { } flush(): string[] { - if (!this.buffer.length && !this.trailingCR) { + if (!this.buffer.length) { return []; } + return this.decode('\n'); + } +} - const lines = [this.buffer.join('')]; - this.buffer = []; - this.trailingCR = false; - return lines; +/** + * This function searches the buffer for the end patterns, (\r or \n) + * and returns an object with the index preceding the matched newline and the + * index after the newline char. `null` is returned if no new line is found. + * + * ```ts + * findNewLineIndex('abc\ndef') -> { preceding: 2, index: 3 } + * ``` + */ +function findNewlineIndex( + buffer: Uint8Array, + startIndex: number | null, +): { preceding: number; index: number; carriage: boolean } | null { + const newline = 0x0a; // \n + const carriage = 0x0d; // \r + + for (let i = startIndex ?? 0; i < buffer.length; i++) { + if (buffer[i] === newline) { + return { preceding: i, index: i + 1, carriage: false }; + } + + if (buffer[i] === carriage) { + return { preceding: i, index: i + 1, carriage: true }; + } } + + return null; +} + +export function findDoubleNewlineIndex(buffer: Uint8Array): number { + // This function searches the buffer for the end patterns (\r\r, \n\n, \r\n\r\n) + // and returns the index right after the first occurrence of any pattern, + // or -1 if none of the patterns are found. + const newline = 0x0a; // \n + const carriage = 0x0d; // \r + + for (let i = 0; i < buffer.length - 1; i++) { + if (buffer[i] === newline && buffer[i + 1] === newline) { + // \n\n + return i + 2; + } + if (buffer[i] === carriage && buffer[i + 1] === carriage) { + // \r\r + return i + 2; + } + if ( + buffer[i] === carriage && + buffer[i + 1] === newline && + i + 3 < buffer.length && + buffer[i + 2] === carriage && + buffer[i + 3] === newline + ) { + // \r\n\r\n + return i + 4; + } + } + + return -1; } diff --git a/src/internal/detect-platform.ts b/src/internal/detect-platform.ts new file mode 100644 index 000000000..c5e273b97 --- /dev/null +++ b/src/internal/detect-platform.ts @@ -0,0 +1,196 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { VERSION } from '../version'; + +export const isRunningInBrowser = () => { + return ( + // @ts-ignore + typeof window !== 'undefined' && + // @ts-ignore + typeof window.document !== 'undefined' && + // @ts-ignore + typeof navigator !== 'undefined' + ); +}; + +type DetectedPlatform = 'deno' | 'node' | 'edge' | 'unknown'; + +/** + * Note this does not detect 'browser'; for that, use getBrowserInfo(). + */ +function getDetectedPlatform(): DetectedPlatform { + if (typeof Deno !== 'undefined' && Deno.build != null) { + return 'deno'; + } + if (typeof EdgeRuntime !== 'undefined') { + return 'edge'; + } + if ( + Object.prototype.toString.call( + typeof (globalThis as any).process !== 'undefined' ? (globalThis as any).process : 0, + ) === '[object process]' + ) { + return 'node'; + } + return 'unknown'; +} + +declare const Deno: any; +declare const EdgeRuntime: any; +type Arch = 'x32' | 'x64' | 'arm' | 'arm64' | `other:${string}` | 'unknown'; +type PlatformName = + | 'MacOS' + | 'Linux' + | 'Windows' + | 'FreeBSD' + | 'OpenBSD' + | 'iOS' + | 'Android' + | `Other:${string}` + | 'Unknown'; +type Browser = 'ie' | 'edge' | 'chrome' | 'firefox' | 'safari'; +type PlatformProperties = { + 'X-Stainless-Lang': 'js'; + 'X-Stainless-Package-Version': string; + 'X-Stainless-OS': PlatformName; + 'X-Stainless-Arch': Arch; + 'X-Stainless-Runtime': 'node' | 'deno' | 'edge' | `browser:${Browser}` | 'unknown'; + 'X-Stainless-Runtime-Version': string; +}; +const getPlatformProperties = (): PlatformProperties => { + const detectedPlatform = getDetectedPlatform(); + if (detectedPlatform === 'deno') { + return { + 'X-Stainless-Lang': 'js', + 'X-Stainless-Package-Version': VERSION, + 'X-Stainless-OS': normalizePlatform(Deno.build.os), + 'X-Stainless-Arch': normalizeArch(Deno.build.arch), + 'X-Stainless-Runtime': 'deno', + 'X-Stainless-Runtime-Version': + typeof Deno.version === 'string' ? Deno.version : Deno.version?.deno ?? 'unknown', + }; + } + if (typeof EdgeRuntime !== 'undefined') { + return { + 'X-Stainless-Lang': 'js', + 'X-Stainless-Package-Version': VERSION, + 'X-Stainless-OS': 'Unknown', + 'X-Stainless-Arch': `other:${EdgeRuntime}`, + 'X-Stainless-Runtime': 'edge', + 'X-Stainless-Runtime-Version': (globalThis as any).process.version, + }; + } + // Check if Node.js + if (detectedPlatform === 'node') { + return { + 'X-Stainless-Lang': 'js', + 'X-Stainless-Package-Version': VERSION, + 'X-Stainless-OS': normalizePlatform((globalThis as any).process.platform), + 'X-Stainless-Arch': normalizeArch((globalThis as any).process.arch), + 'X-Stainless-Runtime': 'node', + 'X-Stainless-Runtime-Version': (globalThis as any).process.version, + }; + } + + const browserInfo = getBrowserInfo(); + if (browserInfo) { + return { + 'X-Stainless-Lang': 'js', + 'X-Stainless-Package-Version': VERSION, + 'X-Stainless-OS': 'Unknown', + 'X-Stainless-Arch': 'unknown', + 'X-Stainless-Runtime': `browser:${browserInfo.browser}`, + 'X-Stainless-Runtime-Version': browserInfo.version, + }; + } + + // TODO add support for Cloudflare workers, etc. + return { + 'X-Stainless-Lang': 'js', + 'X-Stainless-Package-Version': VERSION, + 'X-Stainless-OS': 'Unknown', + 'X-Stainless-Arch': 'unknown', + 'X-Stainless-Runtime': 'unknown', + 'X-Stainless-Runtime-Version': 'unknown', + }; +}; + +type BrowserInfo = { + browser: Browser; + version: string; +}; + +declare const navigator: { userAgent: string } | undefined; + +// Note: modified from https://github.com/JS-DevTools/host-environment/blob/b1ab79ecde37db5d6e163c050e54fe7d287d7c92/src/isomorphic.browser.ts +function getBrowserInfo(): BrowserInfo | null { + if (typeof navigator === 'undefined' || !navigator) { + return null; + } + + // NOTE: The order matters here! + const browserPatterns = [ + { key: 'edge' as const, pattern: /Edge(?:\W+(\d+)\.(\d+)(?:\.(\d+))?)?/ }, + { key: 'ie' as const, pattern: /MSIE(?:\W+(\d+)\.(\d+)(?:\.(\d+))?)?/ }, + { key: 'ie' as const, pattern: /Trident(?:.*rv\:(\d+)\.(\d+)(?:\.(\d+))?)?/ }, + { key: 'chrome' as const, pattern: /Chrome(?:\W+(\d+)\.(\d+)(?:\.(\d+))?)?/ }, + { key: 'firefox' as const, pattern: /Firefox(?:\W+(\d+)\.(\d+)(?:\.(\d+))?)?/ }, + { key: 'safari' as const, pattern: /(?:Version\W+(\d+)\.(\d+)(?:\.(\d+))?)?(?:\W+Mobile\S*)?\W+Safari/ }, + ]; + + // Find the FIRST matching browser + for (const { key, pattern } of browserPatterns) { + const match = pattern.exec(navigator.userAgent); + if (match) { + const major = match[1] || 0; + const minor = match[2] || 0; + const patch = match[3] || 0; + + return { browser: key, version: `${major}.${minor}.${patch}` }; + } + } + + return null; +} + +const normalizeArch = (arch: string): Arch => { + // Node docs: + // - https://nodejs.org/api/process.html#processarch + // Deno docs: + // - https://doc.deno.land/deno/stable/~/Deno.build + if (arch === 'x32') return 'x32'; + if (arch === 'x86_64' || arch === 'x64') return 'x64'; + if (arch === 'arm') return 'arm'; + if (arch === 'aarch64' || arch === 'arm64') return 'arm64'; + if (arch) return `other:${arch}`; + return 'unknown'; +}; + +const normalizePlatform = (platform: string): PlatformName => { + // Node platforms: + // - https://nodejs.org/api/process.html#processplatform + // Deno platforms: + // - https://doc.deno.land/deno/stable/~/Deno.build + // - https://github.com/denoland/deno/issues/14799 + + platform = platform.toLowerCase(); + + // NOTE: this iOS check is untested and may not work + // Node does not work natively on IOS, there is a fork at + // https://github.com/nodejs-mobile/nodejs-mobile + // however it is unknown at the time of writing how to detect if it is running + if (platform.includes('ios')) return 'iOS'; + if (platform === 'android') return 'Android'; + if (platform === 'darwin') return 'MacOS'; + if (platform === 'win32') return 'Windows'; + if (platform === 'freebsd') return 'FreeBSD'; + if (platform === 'openbsd') return 'OpenBSD'; + if (platform === 'linux') return 'Linux'; + if (platform) return `Other:${platform}`; + return 'Unknown'; +}; + +let _platformHeaders: PlatformProperties; +export const getPlatformHeaders = () => { + return (_platformHeaders ??= getPlatformProperties()); +}; diff --git a/src/internal/errors.ts b/src/internal/errors.ts new file mode 100644 index 000000000..82c7b14d5 --- /dev/null +++ b/src/internal/errors.ts @@ -0,0 +1,33 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export function isAbortError(err: unknown) { + return ( + typeof err === 'object' && + err !== null && + // Spec-compliant fetch implementations + (('name' in err && (err as any).name === 'AbortError') || + // Expo fetch + ('message' in err && String((err as any).message).includes('FetchRequestCanceledException'))) + ); +} + +export const castToError = (err: any): Error => { + if (err instanceof Error) return err; + if (typeof err === 'object' && err !== null) { + try { + if (Object.prototype.toString.call(err) === '[object Error]') { + // @ts-ignore - not all envs have native support for cause yet + const error = new Error(err.message, err.cause ? { cause: err.cause } : {}); + if (err.stack) error.stack = err.stack; + // @ts-ignore - not all envs have native support for cause yet + if (err.cause && !error.cause) error.cause = err.cause; + if (err.name) error.name = err.name; + return error; + } + } catch {} + try { + return new Error(JSON.stringify(err)); + } catch {} + } + return new Error(err); +}; diff --git a/src/internal/headers.ts b/src/internal/headers.ts new file mode 100644 index 000000000..a110a1204 --- /dev/null +++ b/src/internal/headers.ts @@ -0,0 +1,96 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +type HeaderValue = string | undefined | null; +export type HeadersLike = + | Headers + | readonly [string, HeaderValue][] + | Record + | undefined + | null + | NullableHeaders; + +const brand_privateNullableHeaders = Symbol('brand.privateNullableHeaders'); + +/** + * @internal + * Users can pass explicit nulls to unset default headers. When we parse them + * into a standard headers type we need to preserve that information. + */ +export type NullableHeaders = { + /** Brand check, prevent users from creating a NullableHeaders. */ + [brand_privateNullableHeaders]: true; + /** Parsed headers. */ + values: Headers; + /** Set of lowercase header names explicitly set to null. */ + nulls: Set; +}; + +const isArray = Array.isArray as (val: unknown) => val is readonly unknown[]; + +function* iterateHeaders(headers: HeadersLike): IterableIterator { + if (!headers) return; + + if (brand_privateNullableHeaders in headers) { + const { values, nulls } = headers; + yield* values.entries(); + for (const name of nulls) { + yield [name, null]; + } + return; + } + + let shouldClear = false; + let iter: Iterable; + if (headers instanceof Headers) { + iter = headers.entries(); + } else if (isArray(headers)) { + iter = headers; + } else { + shouldClear = true; + iter = Object.entries(headers ?? {}); + } + for (let row of iter) { + const name = row[0]; + const values = isArray(row[1]) ? row[1] : [row[1]]; + let didClear = false; + for (const value of values) { + if (value === undefined) continue; + + // Objects keys always overwrite older headers, they never append. + // Yield a null to clear the header before adding the new values. + if (shouldClear && !didClear) { + didClear = true; + yield [name, null]; + } + yield [name, value]; + } + } +} + +export const buildHeaders = (newHeaders: HeadersLike[]): NullableHeaders => { + const targetHeaders = new Headers(); + const nullHeaders = new Set(); + const seenHeaders = new Set(); + for (const headers of newHeaders) { + for (const [name, value] of iterateHeaders(headers)) { + const lowerName = name.toLowerCase(); + if (!seenHeaders.has(lowerName)) { + targetHeaders.delete(name); + seenHeaders.add(lowerName); + } + if (value === null) { + targetHeaders.delete(name); + nullHeaders.add(lowerName); + } else { + targetHeaders.append(name, value); + nullHeaders.delete(lowerName); + } + } + } + return { [brand_privateNullableHeaders]: true, values: targetHeaders, nulls: nullHeaders }; +}; + +export const isEmptyHeaders = (headers: HeadersLike) => { + for (const _ of iterateHeaders(headers)) return false; + return true; +}; diff --git a/src/internal/parse.ts b/src/internal/parse.ts new file mode 100644 index 000000000..173991a55 --- /dev/null +++ b/src/internal/parse.ts @@ -0,0 +1,84 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import type { FinalRequestOptions } from './request-options'; +import { Stream } from '../streaming'; +import { type OpenAI } from '../client'; +import { formatRequestDetails, loggerFor } from './utils/log'; +import type { AbstractPage } from '../pagination'; + +export type APIResponseProps = { + response: Response; + options: FinalRequestOptions; + controller: AbortController; + requestLogID: string; + retryOfRequestLogID: string | undefined; + startTime: number; +}; + +export async function defaultParseResponse( + client: OpenAI, + props: APIResponseProps, +): Promise> { + const { response, requestLogID, retryOfRequestLogID, startTime } = props; + const body = await (async () => { + if (props.options.stream) { + loggerFor(client).debug('response', response.status, response.url, response.headers, response.body); + + // Note: there is an invariant here that isn't represented in the type system + // that if you set `stream: true` the response type must also be `Stream` + + if (props.options.__streamClass) { + return props.options.__streamClass.fromSSEResponse(response, props.controller) as any; + } + + return Stream.fromSSEResponse(response, props.controller) as any; + } + + // fetch refuses to read the body when the status code is 204. + if (response.status === 204) { + return null as T; + } + + if (props.options.__binaryResponse) { + return response as unknown as T; + } + + const contentType = response.headers.get('content-type'); + const isJSON = + contentType?.includes('application/json') || contentType?.includes('application/vnd.api+json'); + if (isJSON) { + const json = await response.json(); + return addRequestID(json as T, response); + } + + const text = await response.text(); + return text as unknown as T; + })(); + loggerFor(client).debug( + `[${requestLogID}] response parsed`, + formatRequestDetails({ + retryOfRequestLogID, + url: response.url, + status: response.status, + body, + durationMs: Date.now() - startTime, + }), + ); + return body; +} + +export type WithRequestID = + T extends Array | Response | AbstractPage ? T + : T extends Record ? T & { _request_id?: string | null } + : T; + +export function addRequestID(value: T, response: Response): WithRequestID { + if (!value || typeof value !== 'object' || Array.isArray(value)) { + return value as WithRequestID; + } + + return Object.defineProperty(value, '_request_id', { + value: response.headers.get('x-request-id'), + enumerable: false, + }) as WithRequestID; +} diff --git a/src/internal/request-options.ts b/src/internal/request-options.ts new file mode 100644 index 000000000..1c7a81e0b --- /dev/null +++ b/src/internal/request-options.ts @@ -0,0 +1,40 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { NullableHeaders } from './headers'; + +import type { BodyInit } from './builtin-types'; +import { Stream } from '../streaming'; +import type { HTTPMethod, MergedRequestInit } from './types'; +import { type HeadersLike } from './headers'; + +export type FinalRequestOptions = RequestOptions & { method: HTTPMethod; path: string }; + +export type RequestOptions = { + method?: HTTPMethod; + path?: string; + query?: object | undefined | null; + body?: unknown; + headers?: HeadersLike; + maxRetries?: number; + stream?: boolean | undefined; + timeout?: number; + fetchOptions?: MergedRequestInit; + signal?: AbortSignal | undefined | null; + idempotencyKey?: string; + + __metadata?: Record; + __binaryResponse?: boolean | undefined; + __streamClass?: typeof Stream; +}; + +export type EncodedContent = { bodyHeaders: HeadersLike; body: BodyInit }; +export type RequestEncoder = (request: { headers: NullableHeaders; body: unknown }) => EncodedContent; + +export const FallbackEncoder: RequestEncoder = ({ headers, body }) => { + return { + bodyHeaders: { + 'content-type': 'application/json', + }, + body: JSON.stringify(body), + }; +}; diff --git a/src/internal/shim-types.d.ts b/src/internal/shim-types.d.ts new file mode 100644 index 000000000..fe48144fa --- /dev/null +++ b/src/internal/shim-types.d.ts @@ -0,0 +1,28 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +/** + * Shims for types that we can't always rely on being available globally. + * + * Note: these only exist at the type-level, there is no corresponding runtime + * version for any of these symbols. + */ + +/** + * In order to properly access the global `NodeJS` type, if it's available, we + * need to make use of declaration shadowing. Without this, any checks for the + * presence of `NodeJS.ReadableStream` will fail. + */ +declare namespace NodeJS { + interface ReadableStream {} +} + +type HasProperties = keyof T extends never ? false : true; + +// @ts-ignore +type _ReadableStream = + // @ts-ignore + HasProperties extends true ? NodeJS.ReadableStream : ReadableStream; + +// @ts-ignore +declare const _ReadableStream: unknown extends typeof ReadableStream ? never : typeof ReadableStream; +export { _ReadableStream as ReadableStream }; diff --git a/src/internal/shims.ts b/src/internal/shims.ts new file mode 100644 index 000000000..b1196d141 --- /dev/null +++ b/src/internal/shims.ts @@ -0,0 +1,107 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +/** + * This module provides internal shims and utility functions for environments where certain Node.js or global types may not be available. + * + * These are used to ensure we can provide a consistent behaviour between different JavaScript environments and good error + * messages in cases where an environment isn't fully supported. + */ + +import { type Fetch } from './builtin-types'; +import { type ReadableStream } from './shim-types'; + +export function getDefaultFetch(): Fetch { + if (typeof fetch !== 'undefined') { + return fetch as any; + } + + throw new Error( + '`fetch` is not defined as a global; Either pass `fetch` to the client, `new OpenAI({ fetch })` or polyfill the global, `globalThis.fetch = fetch`', + ); +} + +type ReadableStreamArgs = ConstructorParameters; + +export function makeReadableStream(...args: ReadableStreamArgs): ReadableStream { + const ReadableStream = (globalThis as any).ReadableStream; + if (typeof ReadableStream === 'undefined') { + // Note: All of the platforms / runtimes we officially support already define + // `ReadableStream` as a global, so this should only ever be hit on unsupported runtimes. + throw new Error( + '`ReadableStream` is not defined as a global; You will need to polyfill it, `globalThis.ReadableStream = ReadableStream`', + ); + } + + return new ReadableStream(...args); +} + +export function ReadableStreamFrom(iterable: Iterable | AsyncIterable): ReadableStream { + let iter: AsyncIterator | Iterator = + Symbol.asyncIterator in iterable ? iterable[Symbol.asyncIterator]() : iterable[Symbol.iterator](); + + return makeReadableStream({ + start() {}, + async pull(controller: any) { + const { done, value } = await iter.next(); + if (done) { + controller.close(); + } else { + controller.enqueue(value); + } + }, + async cancel() { + await iter.return?.(); + }, + }); +} + +/** + * Most browsers don't yet have async iterable support for ReadableStream, + * and Node has a very different way of reading bytes from its "ReadableStream". + * + * This polyfill was pulled from https://github.com/MattiasBuelens/web-streams-polyfill/pull/122#issuecomment-1627354490 + */ +export function ReadableStreamToAsyncIterable(stream: any): AsyncIterableIterator { + if (stream[Symbol.asyncIterator]) return stream; + + const reader = stream.getReader(); + return { + async next() { + try { + const result = await reader.read(); + if (result?.done) reader.releaseLock(); // release lock when stream becomes closed + return result; + } catch (e) { + reader.releaseLock(); // release lock when stream becomes errored + throw e; + } + }, + async return() { + const cancelPromise = reader.cancel(); + reader.releaseLock(); + await cancelPromise; + return { done: true, value: undefined }; + }, + [Symbol.asyncIterator]() { + return this; + }, + }; +} + +/** + * Cancels a ReadableStream we don't need to consume. + * See https://undici.nodejs.org/#/?id=garbage-collection + */ +export async function CancelReadableStream(stream: any): Promise { + if (stream === null || typeof stream !== 'object') return; + + if (stream[Symbol.asyncIterator]) { + await stream[Symbol.asyncIterator]().return?.(); + return; + } + + const reader = stream.getReader(); + const cancelPromise = reader.cancel(); + reader.releaseLock(); + await cancelPromise; +} diff --git a/src/internal/shims/crypto.node.d.ts b/src/internal/shims/crypto.node.d.ts new file mode 100644 index 000000000..dc7caac8d --- /dev/null +++ b/src/internal/shims/crypto.node.d.ts @@ -0,0 +1,10 @@ +export declare const crypto: { + /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Crypto/getRandomValues) */ + getRandomValues(array: T): T; + /** + * Available only in secure contexts. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Crypto/randomUUID) + */ + randomUUID?: () => string; +}; diff --git a/src/internal/shims/crypto.node.js b/src/internal/shims/crypto.node.js new file mode 100644 index 000000000..83062a3d7 --- /dev/null +++ b/src/internal/shims/crypto.node.js @@ -0,0 +1,11 @@ +if (typeof require !== 'undefined') { + if (globalThis.crypto) { + exports.crypto = globalThis.crypto; + } else { + try { + // Use [require][0](...) and not require(...) so bundlers don't try to bundle the + // crypto module. + exports.crypto = [require][0]('node:crypto').webcrypto; + } catch (e) {} + } +} diff --git a/src/internal/shims/crypto.node.mjs b/src/internal/shims/crypto.node.mjs new file mode 100644 index 000000000..24c6f3b9e --- /dev/null +++ b/src/internal/shims/crypto.node.mjs @@ -0,0 +1,2 @@ +import * as mod from './crypto.node.js'; +export const crypto = globalThis.crypto || mod.crypto; diff --git a/src/internal/shims/file.node.d.ts b/src/internal/shims/file.node.d.ts new file mode 100644 index 000000000..9dc6b2fcc --- /dev/null +++ b/src/internal/shims/file.node.d.ts @@ -0,0 +1,20 @@ +// The infer is to make TS show it as a nice union type, +// instead of literally `ConstructorParameters[0]` +type FallbackBlobSource = ConstructorParameters[0] extends infer T ? T : never; +/** + * A [`File`](https://developer.mozilla.org/en-US/docs/Web/API/File) provides information about files. + */ +declare class FallbackFile extends Blob { + constructor(sources: FallbackBlobSource, fileName: string, options?: any); + /** + * The name of the `File`. + */ + readonly name: string; + /** + * The last modified date of the `File`. + */ + readonly lastModified: number; +} +export type File = InstanceType; +export const File: typeof globalThis extends { File: infer fileConstructor } ? fileConstructor +: typeof FallbackFile; diff --git a/src/internal/shims/file.node.js b/src/internal/shims/file.node.js new file mode 100644 index 000000000..3f8c2ed68 --- /dev/null +++ b/src/internal/shims/file.node.js @@ -0,0 +1,11 @@ +if (typeof require !== 'undefined') { + if (globalThis.File) { + exports.File = globalThis.File; + } else { + try { + // Use [require][0](...) and not require(...) so bundlers don't try to bundle the + // buffer module. + exports.File = [require][0]('node:buffer').File; + } catch (e) {} + } +} diff --git a/src/internal/shims/file.node.mjs b/src/internal/shims/file.node.mjs new file mode 100644 index 000000000..1f103f5d3 --- /dev/null +++ b/src/internal/shims/file.node.mjs @@ -0,0 +1,2 @@ +import * as mod from './file.node.js'; +export const File = globalThis.File || mod.File; diff --git a/src/internal/to-file.ts b/src/internal/to-file.ts new file mode 100644 index 000000000..69b76d3a6 --- /dev/null +++ b/src/internal/to-file.ts @@ -0,0 +1,152 @@ +import { File } from './shims/file.node.js'; +import { BlobPart, getName, makeFile, isAsyncIterable } from './uploads'; +import type { FilePropertyBag } from './builtin-types'; + +type BlobLikePart = string | ArrayBuffer | ArrayBufferView | BlobLike | DataView; + +/** + * Intended to match DOM Blob, node-fetch Blob, node:buffer Blob, etc. + * Don't add arrayBuffer here, node-fetch doesn't have it + */ +interface BlobLike { + /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Blob/size) */ + readonly size: number; + /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Blob/type) */ + readonly type: string; + /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Blob/text) */ + text(): Promise; + /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Blob/slice) */ + slice(start?: number, end?: number): BlobLike; +} + +/** + * This check adds the arrayBuffer() method type because it is available and used at runtime + */ +const isBlobLike = (value: any): value is BlobLike & { arrayBuffer(): Promise } => + value != null && + typeof value === 'object' && + typeof value.size === 'number' && + typeof value.type === 'string' && + typeof value.text === 'function' && + typeof value.slice === 'function' && + typeof value.arrayBuffer === 'function'; + +/** + * Intended to match DOM File, node:buffer File, undici File, etc. + */ +interface FileLike extends BlobLike { + /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/File/lastModified) */ + readonly lastModified: number; + /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/File/name) */ + readonly name?: string | undefined; +} + +/** + * This check adds the arrayBuffer() method type because it is available and used at runtime + */ +const isFileLike = (value: any): value is FileLike & { arrayBuffer(): Promise } => + value != null && + typeof value === 'object' && + typeof value.name === 'string' && + typeof value.lastModified === 'number' && + isBlobLike(value); + +/** + * Intended to match DOM Response, node-fetch Response, undici Response, etc. + */ +export interface ResponseLike { + url: string; + blob(): Promise; +} + +const isResponseLike = (value: any): value is ResponseLike => + value != null && + typeof value === 'object' && + typeof value.url === 'string' && + typeof value.blob === 'function'; + +export type ToFileInput = + | FileLike + | ResponseLike + | Exclude + | AsyncIterable; + +/** + * Helper for creating a {@link File} to pass to an SDK upload method from a variety of different data formats + * @param value the raw content of the file. Can be an {@link Uploadable}, {@link BlobLikePart}, or {@link AsyncIterable} of {@link BlobLikePart}s + * @param {string=} name the name of the file. If omitted, toFile will try to determine a file name from bits if possible + * @param {Object=} options additional properties + * @param {string=} options.type the MIME type of the content + * @param {number=} options.lastModified the last modified timestamp + * @returns a {@link File} with the given properties + */ +export async function toFile( + value: ToFileInput | PromiseLike, + name?: string | null | undefined, + options?: FilePropertyBag | undefined, +): Promise { + // If it's a promise, resolve it. + value = await value; + + // If we've been given a `File` we don't need to do anything + if (isFileLike(value)) { + if (File && value instanceof File) { + return value; + } + return makeFile([await value.arrayBuffer()], value.name); + } + + if (isResponseLike(value)) { + const blob = await value.blob(); + name ||= new URL(value.url).pathname.split(/[\\/]/).pop(); + + return makeFile(await getBytes(blob), name, options); + } + + const parts = await getBytes(value); + + name ||= getName(value); + + if (!options?.type) { + const type = parts.find((part) => typeof part === 'object' && 'type' in part && part.type); + if (typeof type === 'string') { + options = { ...options, type }; + } + } + + return makeFile(parts, name, options); +} + +async function getBytes(value: BlobLikePart | AsyncIterable): Promise> { + let parts: Array = []; + if ( + typeof value === 'string' || + ArrayBuffer.isView(value) || // includes Uint8Array, Buffer, etc. + value instanceof ArrayBuffer + ) { + parts.push(value); + } else if (isBlobLike(value)) { + parts.push(value instanceof Blob ? value : await value.arrayBuffer()); + } else if ( + isAsyncIterable(value) // includes Readable, ReadableStream, etc. + ) { + for await (const chunk of value) { + parts.push(...(await getBytes(chunk as BlobLikePart))); // TODO, consider validating? + } + } else { + const constructor = value?.constructor?.name; + throw new Error( + `Unexpected data type: ${typeof value}${ + constructor ? `; constructor: ${constructor}` : '' + }${propsForError(value)}`, + ); + } + + return parts; +} + +function propsForError(value: unknown): string { + if (typeof value !== 'object' || value === null) return ''; + const props = Object.getOwnPropertyNames(value); + return `; props: [${props.map((p) => `"${p}"`).join(', ')}]`; +} diff --git a/src/internal/types.ts b/src/internal/types.ts new file mode 100644 index 000000000..50c16e9d2 --- /dev/null +++ b/src/internal/types.ts @@ -0,0 +1,98 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export type PromiseOrValue = T | Promise; +export type HTTPMethod = 'get' | 'post' | 'put' | 'patch' | 'delete'; + +export type KeysEnum = { [P in keyof Required]: true }; + +type NotAny = [unknown] extends [T] ? never : T; +type Literal = PropertyKey extends T ? never : T; +type MappedLiteralKeys = T extends any ? Literal : never; +type MappedIndex = + T extends any ? + K extends keyof T ? + T[K] + : never + : never; + +/** + * Some environments overload the global fetch function, and Parameters only gets the last signature. + */ +type OverloadedParameters = + T extends ( + { + (...args: infer A): unknown; + (...args: infer B): unknown; + (...args: infer C): unknown; + (...args: infer D): unknown; + } + ) ? + A | B | C | D + : T extends ( + { + (...args: infer A): unknown; + (...args: infer B): unknown; + (...args: infer C): unknown; + } + ) ? + A | B | C + : T extends ( + { + (...args: infer A): unknown; + (...args: infer B): unknown; + } + ) ? + A | B + : T extends (...args: infer A) => unknown ? A + : never; + +/* eslint-disable */ +/** + * These imports attempt to get types from a parent package's dependencies. + * Unresolved bare specifiers can trigger [automatic type acquisition][1] in some projects, which + * would cause typescript to show types not present at runtime. To avoid this, we import + * directly from parent node_modules folders. + * + * We need to check multiple levels because we don't know what directory structure we'll be in. + * For example, pnpm generates directories like this: + * ``` + * node_modules + * ├── .pnpm + * │ └── pkg@1.0.0 + * │ └── node_modules + * │ └── pkg + * │ └── internal + * │ └── types.d.ts + * ├── pkg -> .pnpm/pkg@1.0.0/node_modules/pkg + * └── undici + * ``` + * + * [1]: https://www.typescriptlang.org/tsconfig/#typeAcquisition + */ +/** @ts-ignore For users with \@types/node */ +type UndiciTypesRequestInit = NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny; +/** @ts-ignore For users with undici */ +type UndiciRequestInit = NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny; +/** @ts-ignore For users with \@types/bun */ +type BunRequestInit = globalThis.FetchRequestInit; +/** @ts-ignore For users with node-fetch */ +type NodeFetchRequestInit = NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny; +/** @ts-ignore For users who use Deno */ +type FetchRequestInit = NonNullable[1]>; +/* eslint-enable */ + +type RequestInits = + | NotAny + | NotAny + | NotAny + | NotAny + | NotAny + | NotAny; + +/** + * This type contains `RequestInit` options that may be available on the current runtime, + * including per-platform extensions like `dispatcher`, `agent`, `client`, etc. + */ +export type MergedRequestInit = { + [K in MappedLiteralKeys]?: MappedIndex | undefined; +}; diff --git a/src/internal/uploads.ts b/src/internal/uploads.ts new file mode 100644 index 000000000..2c286497c --- /dev/null +++ b/src/internal/uploads.ts @@ -0,0 +1,178 @@ +import { type RequestOptions } from './request-options'; +import type { FilePropertyBag, Fetch } from './builtin-types'; +import type { OpenAI } from '../client'; +import { File } from './shims/file.node.js'; +import { ReadableStreamFrom } from './shims'; + +export type BlobPart = string | ArrayBuffer | ArrayBufferView | Blob | DataView; +type FsReadStream = AsyncIterable & { path: string | { toString(): string } }; + +// https://github.com/oven-sh/bun/issues/5980 +interface BunFile extends Blob { + readonly name?: string | undefined; +} + +/** + * Typically, this is a native "File" class. + * + * We provide the {@link toFile} utility to convert a variety of objects + * into the File class. + * + * For convenience, you can also pass a fetch Response, or in Node, + * the result of fs.createReadStream(). + */ +export type Uploadable = File | Response | FsReadStream | BunFile; + +/** + * Construct a `File` instance. This is used to ensure a helpful error is thrown + * for environments that don't define a global `File` yet. + */ +export function makeFile( + fileBits: BlobPart[], + fileName: string | undefined, + options?: FilePropertyBag, +): File { + if (typeof File === 'undefined') { + throw new Error('`File` is not defined as a global which is required for file uploads'); + } + + return new File(fileBits as any, fileName ?? 'unknown_file', options); +} + +export function getName(value: any): string | undefined { + return ( + ( + (typeof value === 'object' && + value !== null && + (('name' in value && value.name && String(value.name)) || + ('url' in value && value.url && String(value.url)) || + ('filename' in value && value.filename && String(value.filename)) || + ('path' in value && value.path && String(value.path)))) || + '' + ) + .split(/[\\/]/) + .pop() || undefined + ); +} + +export const isAsyncIterable = (value: any): value is AsyncIterable => + value != null && typeof value === 'object' && typeof value[Symbol.asyncIterator] === 'function'; + +/** + * Returns a multipart/form-data request if any part of the given request body contains a File / Blob value. + * Otherwise returns the request as is. + */ +export const maybeMultipartFormRequestOptions = async ( + opts: RequestOptions, + fetch: OpenAI | Fetch, +): Promise => { + if (!hasUploadableValue(opts.body)) return opts; + + return { ...opts, body: await createForm(opts.body, fetch) }; +}; + +type MultipartFormRequestOptions = Omit & { body: unknown }; + +export const multipartFormRequestOptions = async ( + opts: MultipartFormRequestOptions, + fetch: OpenAI | Fetch, +): Promise => { + return { ...opts, body: await createForm(opts.body, fetch) }; +}; + +const supportsFormDataMap = new WeakMap>(); + +/** + * node-fetch doesn't support the global FormData object in recent node versions. Instead of sending + * properly-encoded form data, it just stringifies the object, resulting in a request body of "[object FormData]". + * This function detects if the fetch function provided supports the global FormData object to avoid + * confusing error messages later on. + */ +function supportsFormData(fetchObject: OpenAI | Fetch): Promise { + const fetch: Fetch = typeof fetchObject === 'function' ? fetchObject : (fetchObject as any).fetch; + const cached = supportsFormDataMap.get(fetch); + if (cached) return cached; + const promise = (async () => { + try { + const FetchResponse = ( + 'Response' in fetch ? + fetch.Response + : (await fetch('data:,')).constructor) as typeof Response; + const data = new FormData(); + if (data.toString() === (await new FetchResponse(data).text())) { + return false; + } + return true; + } catch { + // avoid false negatives + return true; + } + })(); + supportsFormDataMap.set(fetch, promise); + return promise; +} + +export const createForm = async >( + body: T | undefined, + fetch: OpenAI | Fetch, +): Promise => { + if (!(await supportsFormData(fetch))) { + throw new TypeError( + 'The provided fetch function does not support file uploads with the current global FormData class.', + ); + } + const form = new FormData(); + await Promise.all(Object.entries(body || {}).map(([key, value]) => addFormValue(form, key, value))); + return form; +}; + +// We check for Blob not File because Bun.File doesn't inherit from File, +// but they both inherit from Blob and have a `name` property at runtime. +const isNamedBlob = (value: object) => + (File && value instanceof File) || (value instanceof Blob && 'name' in value); + +const isUploadable = (value: unknown) => + typeof value === 'object' && + value !== null && + (value instanceof Response || isAsyncIterable(value) || isNamedBlob(value)); + +const hasUploadableValue = (value: unknown): boolean => { + if (isUploadable(value)) return true; + if (Array.isArray(value)) return value.some(hasUploadableValue); + if (value && typeof value === 'object') { + for (const k in value) { + if (hasUploadableValue((value as any)[k])) return true; + } + } + return false; +}; + +const addFormValue = async (form: FormData, key: string, value: unknown): Promise => { + if (value === undefined) return; + if (value == null) { + throw new TypeError( + `Received null for "${key}"; to pass null in FormData, you must use the string 'null'`, + ); + } + + // TODO: make nested formats configurable + if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') { + form.append(key, String(value)); + } else if (value instanceof Response) { + form.append(key, makeFile([await value.blob()], getName(value))); + } else if (isAsyncIterable(value)) { + form.append(key, makeFile([await new Response(ReadableStreamFrom(value)).blob()], getName(value))); + } else if (isNamedBlob(value)) { + form.append(key, value, getName(value)); + } else if (Array.isArray(value)) { + await Promise.all(value.map((entry) => addFormValue(form, key + '[]', entry))); + } else if (typeof value === 'object') { + await Promise.all( + Object.entries(value).map(([name, prop]) => addFormValue(form, `${key}[${name}]`, prop)), + ); + } else { + throw new TypeError( + `Invalid value given to form, expected a string, number, boolean, object, Array, File or Blob but got ${value} instead`, + ); + } +}; diff --git a/src/internal/utils.ts b/src/internal/utils.ts new file mode 100644 index 000000000..3cbfacce2 --- /dev/null +++ b/src/internal/utils.ts @@ -0,0 +1,8 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export * from './utils/values'; +export * from './utils/base64'; +export * from './utils/env'; +export * from './utils/log'; +export * from './utils/uuid'; +export * from './utils/sleep'; diff --git a/src/internal/utils/base64.ts b/src/internal/utils/base64.ts new file mode 100644 index 000000000..978bacde2 --- /dev/null +++ b/src/internal/utils/base64.ts @@ -0,0 +1,37 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { OpenAIError } from '../../error'; + +export const toBase64 = (data: string | Uint8Array | null | undefined): string => { + if (!data) return ''; + + if (typeof data === 'string') { + data = new (globalThis as any).TextEncoder().encode(data); + } + + if (typeof (globalThis as any).Buffer !== 'undefined') { + return (globalThis as any).Buffer.from(data).toString('base64'); + } + + if (typeof btoa !== 'undefined') { + return btoa(String.fromCharCode.apply(null, data as any)); + } + + throw new OpenAIError('Cannot generate base64 string; Expected `Buffer` or `btoa` to be defined'); +}; + +export const fromBase64 = (str: string): Uint8Array => { + if (typeof (globalThis as any).Buffer !== 'undefined') { + return new Uint8Array((globalThis as any).Buffer.from(str, 'base64')); + } + + if (typeof atob !== 'undefined') { + return new Uint8Array( + atob(str) + .split('') + .map((c) => c.charCodeAt(0)), + ); + } + + throw new OpenAIError('Cannot decode base64 string; Expected `Buffer` or `atob` to be defined'); +}; diff --git a/src/internal/utils/env.ts b/src/internal/utils/env.ts new file mode 100644 index 000000000..2d8480077 --- /dev/null +++ b/src/internal/utils/env.ts @@ -0,0 +1,18 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +/** + * Read an environment variable. + * + * Trims beginning and trailing whitespace. + * + * Will return undefined if the environment variable doesn't exist or cannot be accessed. + */ +export const readEnv = (env: string): string | undefined => { + if (typeof (globalThis as any).process !== 'undefined') { + return (globalThis as any).process.env?.[env]?.trim() ?? undefined; + } + if (typeof (globalThis as any).Deno !== 'undefined') { + return (globalThis as any).Deno.env?.get?.(env)?.trim(); + } + return undefined; +}; diff --git a/src/internal/utils/log.ts b/src/internal/utils/log.ts new file mode 100644 index 000000000..f75d46bba --- /dev/null +++ b/src/internal/utils/log.ts @@ -0,0 +1,98 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import type { LogLevel, Logger } from '../../client'; +import { type OpenAI } from '../../client'; +import { RequestOptions } from '../request-options'; + +const levelNumbers = { + off: 0, + error: 200, + warn: 300, + info: 400, + debug: 500, +}; + +function noop() {} + +function makeLogFn(fnLevel: keyof Logger, logger: Logger | undefined, logLevel: LogLevel) { + if (!logger || levelNumbers[fnLevel] > levelNumbers[logLevel]) { + return noop; + } else { + // Don't wrap logger functions, we want the stacktrace intact! + return logger[fnLevel].bind(logger); + } +} + +const noopLogger = { + error: noop, + warn: noop, + info: noop, + debug: noop, +}; + +let cachedLoggers = new WeakMap(); + +export function loggerFor(client: OpenAI): Logger { + const logger = client.logger; + const logLevel = client.logLevel ?? 'off'; + if (!logger) { + return noopLogger; + } + + const cachedLogger = cachedLoggers.get(logger); + if (cachedLogger && cachedLogger[0] === logLevel) { + return cachedLogger[1]; + } + + const levelLogger = { + error: makeLogFn('error', logger, logLevel), + warn: makeLogFn('warn', logger, logLevel), + info: makeLogFn('info', logger, logLevel), + debug: makeLogFn('debug', logger, logLevel), + }; + + cachedLoggers.set(logger, [logLevel, levelLogger]); + + return levelLogger; +} + +export const formatRequestDetails = (details: { + options?: RequestOptions | undefined; + headers?: Headers | Record | undefined; + retryOfRequestLogID?: string | undefined; + retryOf?: string | undefined; + url?: string | undefined; + status?: number | undefined; + method?: string | undefined; + durationMs?: number | undefined; + message?: unknown; + body?: unknown; +}) => { + if (details.options) { + details.options = { ...details.options }; + delete details.options['headers']; // redundant + leaks internals + } + if (details.headers) { + details.headers = Object.fromEntries( + (details.headers instanceof Headers ? [...details.headers] : Object.entries(details.headers)).map( + ([name, value]) => [ + name, + ( + name.toLowerCase() === 'authorization' || + name.toLowerCase() === 'cookie' || + name.toLowerCase() === 'set-cookie' + ) ? + '***' + : value, + ], + ), + ); + } + if ('retryOfRequestLogID' in details) { + if (details.retryOfRequestLogID) { + details.retryOf = details.retryOfRequestLogID; + } + delete details.retryOfRequestLogID; + } + return details; +}; diff --git a/src/internal/utils/path.ts b/src/internal/utils/path.ts new file mode 100644 index 000000000..b40291903 --- /dev/null +++ b/src/internal/utils/path.ts @@ -0,0 +1,63 @@ +import { OpenAIError } from '../../error'; + +/** + * Percent-encode everything that isn't safe to have in a path without encoding safe chars. + * + * Taken from https://datatracker.ietf.org/doc/html/rfc3986#section-3.3: + * > unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" + * > sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "=" + * > pchar = unreserved / pct-encoded / sub-delims / ":" / "@" + */ +export function encodeURIPath(str: string) { + return str.replace(/[^A-Za-z0-9\-._~!$&'()*+,;=:@]+/g, encodeURIComponent); +} + +export const createPathTagFunction = (pathEncoder = encodeURIPath) => + function path(statics: readonly string[], ...params: readonly unknown[]): string { + // If there are no params, no processing is needed. + if (statics.length === 1) return statics[0]!; + + let postPath = false; + const path = statics.reduce((previousValue, currentValue, index) => { + if (/[?#]/.test(currentValue)) { + postPath = true; + } + return ( + previousValue + + currentValue + + (index === params.length ? '' : (postPath ? encodeURIComponent : pathEncoder)(String(params[index]))) + ); + }, ''); + + const pathOnly = path.split(/[?#]/, 1)[0]!; + const invalidSegments = []; + const invalidSegmentPattern = /(?<=^|\/)(?:\.|%2e){1,2}(?=\/|$)/gi; + let match; + + // Find all invalid segments + while ((match = invalidSegmentPattern.exec(pathOnly)) !== null) { + invalidSegments.push({ + start: match.index, + length: match[0].length, + }); + } + + if (invalidSegments.length > 0) { + let lastEnd = 0; + const underline = invalidSegments.reduce((acc, segment) => { + const spaces = ' '.repeat(segment.start - lastEnd); + const arrows = '^'.repeat(segment.length); + lastEnd = segment.start + segment.length; + return acc + spaces + arrows; + }, ''); + + throw new OpenAIError(`Path parameters result in path with invalid segments:\n${path}\n${underline}`); + } + + return path; + }; + +/** + * URI-encodes path params and ensures no unsafe /./ or /../ path segments are introduced. + */ +export const path = createPathTagFunction(encodeURIPath); diff --git a/src/internal/utils/sleep.ts b/src/internal/utils/sleep.ts new file mode 100644 index 000000000..65e52962b --- /dev/null +++ b/src/internal/utils/sleep.ts @@ -0,0 +1,3 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms)); diff --git a/src/internal/utils/uuid.ts b/src/internal/utils/uuid.ts new file mode 100644 index 000000000..1349c42c3 --- /dev/null +++ b/src/internal/utils/uuid.ts @@ -0,0 +1,13 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { crypto } from '../shims/crypto.node.js'; + +/** + * https://stackoverflow.com/a/2117523 + */ +export function uuid4() { + if (crypto.randomUUID) return crypto.randomUUID(); + return '10000000-1000-4000-8000-100000000000'.replace(/[018]/g, (c) => + (+c ^ (crypto.getRandomValues(new Uint8Array(1))[0]! & (15 >> (+c / 4)))).toString(16), + ); +} diff --git a/src/internal/utils/values.ts b/src/internal/utils/values.ts new file mode 100644 index 000000000..bb66cfdc1 --- /dev/null +++ b/src/internal/utils/values.ts @@ -0,0 +1,94 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { OpenAIError } from '../../error'; + +// https://url.spec.whatwg.org/#url-scheme-string +const startsWithSchemeRegexp = /^[a-z][a-z0-9+.-]*:/i; + +export const isAbsoluteURL = (url: string): boolean => { + return startsWithSchemeRegexp.test(url); +}; + +/** Returns an object if the given value isn't an object, otherwise returns as-is */ +export function maybeObj(x: unknown): object { + if (typeof x !== 'object') { + return {}; + } + + return x ?? {}; +} + +// https://stackoverflow.com/a/34491287 +export function isEmptyObj(obj: Object | null | undefined): boolean { + if (!obj) return true; + for (const _k in obj) return false; + return true; +} + +// https://eslint.org/docs/latest/rules/no-prototype-builtins +export function hasOwn(obj: T, key: PropertyKey): key is keyof T { + return Object.prototype.hasOwnProperty.call(obj, key); +} + +export function isObj(obj: unknown): obj is Record { + return obj != null && typeof obj === 'object' && !Array.isArray(obj); +} + +export const ensurePresent = (value: T | null | undefined): T => { + if (value == null) { + throw new OpenAIError(`Expected a value to be given but received ${value} instead.`); + } + + return value; +}; + +export const validatePositiveInteger = (name: string, n: unknown): number => { + if (typeof n !== 'number' || !Number.isInteger(n)) { + throw new OpenAIError(`${name} must be an integer`); + } + if (n < 0) { + throw new OpenAIError(`${name} must be a positive integer`); + } + return n; +}; + +export const coerceInteger = (value: unknown): number => { + if (typeof value === 'number') return Math.round(value); + if (typeof value === 'string') return parseInt(value, 10); + + throw new OpenAIError(`Could not coerce ${value} (type: ${typeof value}) into a number`); +}; + +export const coerceFloat = (value: unknown): number => { + if (typeof value === 'number') return value; + if (typeof value === 'string') return parseFloat(value); + + throw new OpenAIError(`Could not coerce ${value} (type: ${typeof value}) into a number`); +}; + +export const coerceBoolean = (value: unknown): boolean => { + if (typeof value === 'boolean') return value; + if (typeof value === 'string') return value === 'true'; + return Boolean(value); +}; + +export const maybeCoerceInteger = (value: unknown): number | undefined => { + if (value === undefined) { + return undefined; + } + return coerceInteger(value); +}; + +export const maybeCoerceFloat = (value: unknown): number | undefined => { + if (value === undefined) { + return undefined; + } + return coerceFloat(value); +}; + +export const maybeCoerceBoolean = (value: unknown): boolean | undefined => { + if (value === undefined) { + return undefined; + } + return coerceBoolean(value); +}; diff --git a/src/lib/AbstractChatCompletionRunner.ts b/src/lib/AbstractChatCompletionRunner.ts index 406f5a431..9f31ac119 100644 --- a/src/lib/AbstractChatCompletionRunner.ts +++ b/src/lib/AbstractChatCompletionRunner.ts @@ -1,4 +1,3 @@ -import * as Core from '../core'; import { type CompletionUsage } from '../resources/completions'; import { type ChatCompletion, @@ -14,19 +13,17 @@ import { type BaseFunctionsArgs, RunnableToolFunction, } from './RunnableFunction'; -import { ChatCompletionFunctionRunnerParams, ChatCompletionToolRunnerParams } from './ChatCompletionRunner'; -import { - ChatCompletionStreamingFunctionRunnerParams, - ChatCompletionStreamingToolRunnerParams, -} from './ChatCompletionStreamingRunner'; +import { ChatCompletionToolRunnerParams } from './ChatCompletionRunner'; +import { ChatCompletionStreamingToolRunnerParams } from './ChatCompletionStreamingRunner'; import { isAssistantMessage, isFunctionMessage, isToolMessage } from './chatCompletionUtils'; import { BaseEvents, EventStream } from './EventStream'; import { ParsedChatCompletion } from '../resources/beta/chat/completions'; import OpenAI from '../index'; import { isAutoParsableTool, parseChatCompletion } from '../lib/parser'; +import { RequestOptions } from '../internal/request-options'; const DEFAULT_MAX_CHAT_COMPLETIONS = 10; -export interface RunnerOptions extends Core.RequestOptions { +export interface RunnerOptions extends RequestOptions { /** How many requests to make before canceling. Default 10. */ maxChatCompletions?: number; } @@ -238,7 +235,7 @@ export class AbstractChatCompletionRunner< protected async _createChatCompletion( client: OpenAI, params: ChatCompletionCreateParams, - options?: Core.RequestOptions, + options?: RequestOptions, ): Promise> { const signal = options?.signal; if (signal) { @@ -258,7 +255,7 @@ export class AbstractChatCompletionRunner< protected async _runChatCompletion( client: OpenAI, params: ChatCompletionCreateParams, - options?: Core.RequestOptions, + options?: RequestOptions, ): Promise { for (const message of params.messages) { this._addMessage(message, false); @@ -266,91 +263,6 @@ export class AbstractChatCompletionRunner< return await this._createChatCompletion(client, params, options); } - protected async _runFunctions( - client: OpenAI, - params: - | ChatCompletionFunctionRunnerParams - | ChatCompletionStreamingFunctionRunnerParams, - options?: RunnerOptions, - ) { - const role = 'function' as const; - const { function_call = 'auto', stream, ...restParams } = params; - const singleFunctionToCall = typeof function_call !== 'string' && function_call?.name; - const { maxChatCompletions = DEFAULT_MAX_CHAT_COMPLETIONS } = options || {}; - - const functionsByName: Record> = {}; - for (const f of params.functions) { - functionsByName[f.name || f.function.name] = f; - } - - const functions: ChatCompletionCreateParams.Function[] = params.functions.map( - (f): ChatCompletionCreateParams.Function => ({ - name: f.name || f.function.name, - parameters: f.parameters as Record, - description: f.description, - }), - ); - - for (const message of params.messages) { - this._addMessage(message, false); - } - - for (let i = 0; i < maxChatCompletions; ++i) { - const chatCompletion: ChatCompletion = await this._createChatCompletion( - client, - { - ...restParams, - function_call, - functions, - messages: [...this.messages], - }, - options, - ); - const message = chatCompletion.choices[0]?.message; - if (!message) { - throw new OpenAIError(`missing message in ChatCompletion response`); - } - if (!message.function_call) return; - const { name, arguments: args } = message.function_call; - const fn = functionsByName[name]; - if (!fn) { - const content = `Invalid function_call: ${JSON.stringify(name)}. Available options are: ${functions - .map((f) => JSON.stringify(f.name)) - .join(', ')}. Please try again`; - - this._addMessage({ role, name, content }); - continue; - } else if (singleFunctionToCall && singleFunctionToCall !== name) { - const content = `Invalid function_call: ${JSON.stringify(name)}. ${JSON.stringify( - singleFunctionToCall, - )} requested. Please try again`; - - this._addMessage({ role, name, content }); - continue; - } - - let parsed; - try { - parsed = isRunnableFunctionWithParse(fn) ? await fn.parse(args) : args; - } catch (error) { - this._addMessage({ - role, - name, - content: error instanceof Error ? error.message : String(error), - }); - continue; - } - - // @ts-expect-error it can't rule out `never` type. - const rawContent = await fn.function(parsed, this); - const content = this.#stringifyFunctionCallResult(rawContent); - - this._addMessage({ role, name, content }); - - if (singleFunctionToCall) return; - } - } - protected async _runTools( client: OpenAI, params: diff --git a/src/lib/AssistantStream.ts b/src/lib/AssistantStream.ts index caf68e7dd..b9226bf3a 100644 --- a/src/lib/AssistantStream.ts +++ b/src/lib/AssistantStream.ts @@ -9,8 +9,7 @@ import { MessageDelta, MessageContent, } from '../resources/beta/threads/messages'; -import * as Core from '../core'; -import { RequestOptions } from '../core'; +import { RequestOptions } from '../internal/request-options'; import { Run, RunCreateParamsBase, @@ -19,7 +18,7 @@ import { RunSubmitToolOutputsParamsBase, RunSubmitToolOutputsParamsStreaming, } from '../resources/beta/threads/runs/runs'; -import { type ReadableStream } from '../_shims/index'; +import { type ReadableStream } from '../internal/shim-types'; import { Stream } from '../streaming'; import { APIUserAbortError, OpenAIError } from '../error'; import { @@ -31,6 +30,7 @@ import { import { RunStep, RunStepDelta, ToolCall, ToolCallDelta } from '../resources/beta/threads/runs/steps'; import { ThreadCreateAndRunParamsBase, Threads } from '../resources/beta/threads/threads'; import { BaseEvents, EventStream } from './EventStream'; +import { isObj } from '../internal/utils'; export interface AssistantStreamEvents extends BaseEvents { run: (run: Run) => void; @@ -163,7 +163,7 @@ export class AssistantStream protected async _fromReadableStream( readableStream: ReadableStream, - options?: Core.RequestOptions, + options?: RequestOptions, ): Promise { const signal = options?.signal; if (signal) { @@ -187,7 +187,6 @@ export class AssistantStream } static createToolAssistantStream( - threadId: string, runId: string, runs: Runs, params: RunSubmitToolOutputsParamsStream, @@ -195,7 +194,7 @@ export class AssistantStream ): AssistantStream { const runner = new AssistantStream(); runner._run(() => - runner._runToolAssistantStream(threadId, runId, runs, params, { + runner._runToolAssistantStream(runId, runs, params, { ...options, headers: { ...options?.headers, 'X-Stainless-Helper-Method': 'stream' }, }), @@ -205,10 +204,9 @@ export class AssistantStream protected async _createToolAssistantStream( run: Runs, - threadId: string, runId: string, params: RunSubmitToolOutputsParamsStream, - options?: Core.RequestOptions, + options?: RequestOptions, ): Promise { const signal = options?.signal; if (signal) { @@ -217,7 +215,7 @@ export class AssistantStream } const body: RunSubmitToolOutputsParamsStreaming = { ...params, stream: true }; - const stream = await run.submitToolOutputs(threadId, runId, body, { + const stream = await run.submitToolOutputs(runId, body, { ...options, signal: this.controller.signal, }); @@ -303,7 +301,7 @@ export class AssistantStream protected async _createThreadAssistantStream( thread: Threads, params: ThreadCreateAndRunParamsBase, - options?: Core.RequestOptions, + options?: RequestOptions, ): Promise { const signal = options?.signal; if (signal) { @@ -330,7 +328,7 @@ export class AssistantStream run: Runs, threadId: string, params: RunCreateParamsBase, - options?: Core.RequestOptions, + options?: RequestOptions, ): Promise { const signal = options?.signal; if (signal) { @@ -370,6 +368,7 @@ export class AssistantStream case 'thread.run.in_progress': case 'thread.run.requires_action': case 'thread.run.completed': + case 'thread.run.incomplete': case 'thread.run.failed': case 'thread.run.cancelling': case 'thread.run.cancelled': @@ -400,6 +399,8 @@ export class AssistantStream throw new Error( 'Encountered an error event in event processing - errors should be processed earlier', ); + default: + assertNever(event); } } @@ -676,7 +677,7 @@ export class AssistantStream accValue += deltaValue; } else if (typeof accValue === 'number' && typeof deltaValue === 'number') { accValue += deltaValue; - } else if (Core.isObj(accValue) && Core.isObj(deltaValue)) { + } else if (isObj(accValue) && isObj(deltaValue)) { accValue = this.accumulateDelta(accValue as Record, deltaValue as Record); } else if (Array.isArray(accValue) && Array.isArray(deltaValue)) { if (accValue.every((x) => typeof x === 'string' || typeof x === 'number')) { @@ -685,7 +686,7 @@ export class AssistantStream } for (const deltaEntry of deltaValue) { - if (!Core.isObj(deltaEntry)) { + if (!isObj(deltaEntry)) { throw new Error(`Expected array delta entry to be an object but got: ${deltaEntry}`); } @@ -748,7 +749,7 @@ export class AssistantStream protected async _threadAssistantStream( params: ThreadCreateAndRunParamsBase, thread: Threads, - options?: Core.RequestOptions, + options?: RequestOptions, ): Promise { return await this._createThreadAssistantStream(thread, params, options); } @@ -757,18 +758,19 @@ export class AssistantStream threadId: string, runs: Runs, params: RunCreateParamsBase, - options?: Core.RequestOptions, + options?: RequestOptions, ): Promise { return await this._createAssistantStream(runs, threadId, params, options); } protected async _runToolAssistantStream( - threadId: string, runId: string, runs: Runs, params: RunSubmitToolOutputsParamsStream, - options?: Core.RequestOptions, + options?: RequestOptions, ): Promise { - return await this._createToolAssistantStream(runs, threadId, runId, params, options); + return await this._createToolAssistantStream(runs, runId, params, options); } } + +function assertNever(_x: never) {} diff --git a/src/lib/ChatCompletionRunner.ts b/src/lib/ChatCompletionRunner.ts index 9e68e6671..a5edaf741 100644 --- a/src/lib/ChatCompletionRunner.ts +++ b/src/lib/ChatCompletionRunner.ts @@ -2,7 +2,7 @@ import { type ChatCompletionMessageParam, type ChatCompletionCreateParamsNonStreaming, } from '../resources/chat/completions'; -import { type RunnableFunctions, type BaseFunctionsArgs, RunnableTools } from './RunnableFunction'; +import { type BaseFunctionsArgs, RunnableTools } from './RunnableFunction'; import { AbstractChatCompletionRunner, AbstractChatCompletionRunnerEvents, @@ -16,13 +16,6 @@ export interface ChatCompletionRunnerEvents extends AbstractChatCompletionRunner content: (content: string) => void; } -export type ChatCompletionFunctionRunnerParams = Omit< - ChatCompletionCreateParamsNonStreaming, - 'functions' -> & { - functions: RunnableFunctions; -}; - export type ChatCompletionToolRunnerParams = Omit< ChatCompletionCreateParamsNonStreaming, 'tools' @@ -34,21 +27,6 @@ export class ChatCompletionRunner extends AbstractChatCompletion ChatCompletionRunnerEvents, ParsedT > { - /** @deprecated - please use `runTools` instead. */ - static runFunctions( - client: OpenAI, - params: ChatCompletionFunctionRunnerParams, - options?: RunnerOptions, - ): ChatCompletionRunner { - const runner = new ChatCompletionRunner(); - const opts = { - ...options, - headers: { ...options?.headers, 'X-Stainless-Helper-Method': 'runFunctions' }, - }; - runner._run(() => runner._runFunctions(client, params, opts)); - return runner; - } - static runTools( client: OpenAI, params: ChatCompletionToolRunnerParams, diff --git a/src/lib/ChatCompletionStream.ts b/src/lib/ChatCompletionStream.ts index a88f8a23b..ce64e1aad 100644 --- a/src/lib/ChatCompletionStream.ts +++ b/src/lib/ChatCompletionStream.ts @@ -1,4 +1,3 @@ -import * as Core from '../core'; import { OpenAIError, APIUserAbortError, @@ -12,12 +11,13 @@ import { type ChatCompletionCreateParams, type ChatCompletionCreateParamsStreaming, type ChatCompletionCreateParamsBase, + type ChatCompletionRole, } from '../resources/chat/completions'; import { AbstractChatCompletionRunner, type AbstractChatCompletionRunnerEvents, } from './AbstractChatCompletionRunner'; -import { type ReadableStream } from '../_shims/index'; +import { type ReadableStream } from '../internal/shim-types'; import { Stream } from '../streaming'; import OpenAI from '../index'; import { ParsedChatCompletion } from '../resources/beta/chat/completions'; @@ -30,6 +30,7 @@ import { shouldParseToolCall, } from '../lib/parser'; import { partialParse } from '../_vendor/partial-json-parser/parser'; +import { RequestOptions } from '../internal/request-options'; export interface ContentDeltaEvent { delta: string; @@ -158,7 +159,7 @@ export class ChatCompletionStream static createChatCompletion( client: OpenAI, params: ChatCompletionStreamParams, - options?: Core.RequestOptions, + options?: RequestOptions, ): ChatCompletionStream { const runner = new ChatCompletionStream(params as ChatCompletionCreateParamsStreaming); runner._run(() => @@ -368,7 +369,7 @@ export class ChatCompletionStream protected override async _createChatCompletion( client: OpenAI, params: ChatCompletionCreateParams, - options?: Core.RequestOptions, + options?: RequestOptions, ): Promise> { super._createChatCompletion; const signal = options?.signal; @@ -394,7 +395,7 @@ export class ChatCompletionStream protected async _fromReadableStream( readableStream: ReadableStream, - options?: Core.RequestOptions, + options?: RequestOptions, ): Promise { const signal = options?.signal; if (signal) { @@ -797,7 +798,7 @@ export namespace ChatCompletionSnapshot { /** * The role of the author of this message. */ - role?: 'system' | 'user' | 'assistant' | 'function' | 'tool'; + role?: ChatCompletionRole; } export namespace Message { diff --git a/src/lib/ChatCompletionStreamingRunner.ts b/src/lib/ChatCompletionStreamingRunner.ts index ba0c6496f..edd25ab93 100644 --- a/src/lib/ChatCompletionStreamingRunner.ts +++ b/src/lib/ChatCompletionStreamingRunner.ts @@ -3,8 +3,8 @@ import { type ChatCompletionCreateParamsStreaming, } from '../resources/chat/completions'; import { RunnerOptions, type AbstractChatCompletionRunnerEvents } from './AbstractChatCompletionRunner'; -import { type ReadableStream } from '../_shims/index'; -import { RunnableTools, type BaseFunctionsArgs, type RunnableFunctions } from './RunnableFunction'; +import type { ReadableStream } from '../internal/shim-types'; +import { RunnableTools, type BaseFunctionsArgs } from './RunnableFunction'; import { ChatCompletionSnapshot, ChatCompletionStream } from './ChatCompletionStream'; import OpenAI from '../index'; import { AutoParseableTool } from '../lib/parser'; @@ -14,13 +14,6 @@ export interface ChatCompletionStreamEvents extends AbstractChatCompletionRunner chunk: (chunk: ChatCompletionChunk, snapshot: ChatCompletionSnapshot) => void; } -export type ChatCompletionStreamingFunctionRunnerParams = Omit< - ChatCompletionCreateParamsStreaming, - 'functions' -> & { - functions: RunnableFunctions; -}; - export type ChatCompletionStreamingToolRunnerParams = Omit< ChatCompletionCreateParamsStreaming, 'tools' @@ -38,21 +31,6 @@ export class ChatCompletionStreamingRunner return runner; } - /** @deprecated - please use `runTools` instead. */ - static runFunctions( - client: OpenAI, - params: ChatCompletionStreamingFunctionRunnerParams, - options?: RunnerOptions, - ): ChatCompletionStreamingRunner { - const runner = new ChatCompletionStreamingRunner(null); - const opts = { - ...options, - headers: { ...options?.headers, 'X-Stainless-Helper-Method': 'runFunctions' }, - }; - runner._run(() => runner._runFunctions(client, params, opts)); - return runner; - } - static runTools( client: OpenAI, params: ChatCompletionStreamingToolRunnerParams, diff --git a/src/lib/EventEmitter.ts b/src/lib/EventEmitter.ts new file mode 100644 index 000000000..9adeebdc3 --- /dev/null +++ b/src/lib/EventEmitter.ts @@ -0,0 +1,98 @@ +type EventListener = Events[EventType]; + +type EventListeners = Array<{ + listener: EventListener; + once?: boolean; +}>; + +export type EventParameters = { + [Event in EventType]: EventListener extends (...args: infer P) => any ? P : never; +}[EventType]; + +export class EventEmitter any>> { + #listeners: { + [Event in keyof EventTypes]?: EventListeners; + } = {}; + + /** + * Adds the listener function to the end of the listeners array for the event. + * No checks are made to see if the listener has already been added. Multiple calls passing + * the same combination of event and listener will result in the listener being added, and + * called, multiple times. + * @returns this, so that calls can be chained + */ + on(event: Event, listener: EventListener): this { + const listeners: EventListeners = + this.#listeners[event] || (this.#listeners[event] = []); + listeners.push({ listener }); + return this; + } + + /** + * Removes the specified listener from the listener array for the event. + * off() will remove, at most, one instance of a listener from the listener array. If any single + * listener has been added multiple times to the listener array for the specified event, then + * off() must be called multiple times to remove each instance. + * @returns this, so that calls can be chained + */ + off(event: Event, listener: EventListener): this { + const listeners = this.#listeners[event]; + if (!listeners) return this; + const index = listeners.findIndex((l) => l.listener === listener); + if (index >= 0) listeners.splice(index, 1); + return this; + } + + /** + * Adds a one-time listener function for the event. The next time the event is triggered, + * this listener is removed and then invoked. + * @returns this, so that calls can be chained + */ + once(event: Event, listener: EventListener): this { + const listeners: EventListeners = + this.#listeners[event] || (this.#listeners[event] = []); + listeners.push({ listener, once: true }); + return this; + } + + /** + * This is similar to `.once()`, but returns a Promise that resolves the next time + * the event is triggered, instead of calling a listener callback. + * @returns a Promise that resolves the next time given event is triggered, + * or rejects if an error is emitted. (If you request the 'error' event, + * returns a promise that resolves with the error). + * + * Example: + * + * const message = await stream.emitted('message') // rejects if the stream errors + */ + emitted( + event: Event, + ): Promise< + EventParameters extends [infer Param] ? Param + : EventParameters extends [] ? void + : EventParameters + > { + return new Promise((resolve, reject) => { + // TODO: handle errors + this.once(event, resolve as any); + }); + } + + protected _emit( + this: EventEmitter, + event: Event, + ...args: EventParameters + ) { + const listeners: EventListeners | undefined = this.#listeners[event]; + if (listeners) { + this.#listeners[event] = listeners.filter((l) => !l.once) as any; + listeners.forEach(({ listener }: any) => listener(...(args as any))); + } + } + + protected _hasListener(event: keyof EventTypes): boolean { + const listeners = this.#listeners[event]; + return listeners && listeners.length > 0; + } +} diff --git a/src/lib/EventStream.ts b/src/lib/EventStream.ts index d3f485e9d..d1b1cc8d3 100644 --- a/src/lib/EventStream.ts +++ b/src/lib/EventStream.ts @@ -1,3 +1,4 @@ +import { isAbortError } from '../internal/errors'; import { APIUserAbortError, OpenAIError } from '../error'; export class EventStream { @@ -145,7 +146,7 @@ export class EventStream { #handleError(this: EventStream, error: unknown) { this.#errored = true; - if (error instanceof Error && error.name === 'AbortError') { + if (isAbortError(error)) { error = new APIUserAbortError(); } if (error instanceof APIUserAbortError) { diff --git a/src/lib/RunnableFunction.ts b/src/lib/RunnableFunction.ts index a645f5ebe..4d1519d5a 100644 --- a/src/lib/RunnableFunction.ts +++ b/src/lib/RunnableFunction.ts @@ -85,13 +85,6 @@ export function isRunnableFunctionWithParse( export type BaseFunctionsArgs = readonly (object | string)[]; -export type RunnableFunctions = - [any[]] extends [FunctionsArgs] ? readonly RunnableFunction[] - : { - [Index in keyof FunctionsArgs]: Index extends number ? RunnableFunction - : FunctionsArgs[Index]; - }; - export type RunnableTools = [any[]] extends [FunctionsArgs] ? readonly RunnableToolFunction[] : { @@ -99,28 +92,6 @@ export type RunnableTools = : FunctionsArgs[Index]; }; -/** - * This is helper class for passing a `function` and `parse` where the `function` - * argument type matches the `parse` return type. - * - * @deprecated - please use ParsingToolFunction instead. - */ -export class ParsingFunction { - function: RunnableFunctionWithParse['function']; - parse: RunnableFunctionWithParse['parse']; - parameters: RunnableFunctionWithParse['parameters']; - description: RunnableFunctionWithParse['description']; - name?: RunnableFunctionWithParse['name']; - - constructor(input: RunnableFunctionWithParse) { - this.function = input.function; - this.parse = input.parse; - this.parameters = input.parameters; - this.description = input.description; - this.name = input.name; - } -} - /** * This is helper class for passing a `function` and `parse` where the `function` * argument type matches the `parse` return type. diff --git a/src/lib/parser.ts b/src/lib/parser.ts index f2678e312..a750375dc 100644 --- a/src/lib/parser.ts +++ b/src/lib/parser.ts @@ -119,7 +119,15 @@ export function maybeParseChatCompletion< ...completion, choices: completion.choices.map((choice) => ({ ...choice, - message: { ...choice.message, parsed: null, tool_calls: choice.message.tool_calls ?? [] }, + message: { + ...choice.message, + parsed: null, + ...(choice.message.tool_calls ? + { + tool_calls: choice.message.tool_calls, + } + : undefined), + }, })), }; } @@ -144,7 +152,12 @@ export function parseChatCompletion< ...choice, message: { ...choice.message, - tool_calls: choice.message.tool_calls?.map((toolCall) => parseToolCall(params, toolCall)) ?? [], + ...(choice.message.tool_calls ? + { + tool_calls: + choice.message.tool_calls?.map((toolCall) => parseToolCall(params, toolCall)) ?? undefined, + } + : undefined), parsed: choice.message.content && !choice.message.refusal ? parseResponseFormat(params, choice.message.content) diff --git a/src/pagination.ts b/src/pagination.ts index 63644e333..fdcc7e131 100644 --- a/src/pagination.ts +++ b/src/pagination.ts @@ -1,6 +1,116 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { AbstractPage, Response, APIClient, FinalRequestOptions, PageInfo } from './core'; +import { OpenAIError } from './error'; +import { FinalRequestOptions } from './internal/request-options'; +import { defaultParseResponse, WithRequestID } from './internal/parse'; +import { APIPromise } from './api-promise'; +import { type OpenAI } from './client'; +import { type APIResponseProps } from './internal/parse'; +import { maybeObj } from './internal/utils/values'; + +export type PageRequestOptions = Pick; + +export abstract class AbstractPage implements AsyncIterable { + #client: OpenAI; + protected options: FinalRequestOptions; + + protected response: Response; + protected body: unknown; + + constructor(client: OpenAI, response: Response, body: unknown, options: FinalRequestOptions) { + this.#client = client; + this.options = options; + this.response = response; + this.body = body; + } + + abstract nextPageRequestOptions(): PageRequestOptions | null; + + abstract getPaginatedItems(): Item[]; + + hasNextPage(): boolean { + const items = this.getPaginatedItems(); + if (!items.length) return false; + return this.nextPageRequestOptions() != null; + } + + async getNextPage(): Promise { + const nextOptions = this.nextPageRequestOptions(); + if (!nextOptions) { + throw new OpenAIError( + 'No next page expected; please check `.hasNextPage()` before calling `.getNextPage()`.', + ); + } + + return await this.#client.requestAPIList(this.constructor as any, nextOptions); + } + + async *iterPages(): AsyncGenerator { + let page: this = this; + yield page; + while (page.hasNextPage()) { + page = await page.getNextPage(); + yield page; + } + } + + async *[Symbol.asyncIterator](): AsyncGenerator { + for await (const page of this.iterPages()) { + for (const item of page.getPaginatedItems()) { + yield item; + } + } + } +} + +/** + * This subclass of Promise will resolve to an instantiated Page once the request completes. + * + * It also implements AsyncIterable to allow auto-paginating iteration on an unawaited list call, eg: + * + * for await (const item of client.items.list()) { + * console.log(item) + * } + */ +export class PagePromise< + PageClass extends AbstractPage, + Item = ReturnType[number], + > + extends APIPromise + implements AsyncIterable +{ + constructor( + client: OpenAI, + request: Promise, + Page: new (...args: ConstructorParameters) => PageClass, + ) { + super( + client, + request, + async (client, props) => + new Page( + client, + props.response, + await defaultParseResponse(client, props), + props.options, + ) as WithRequestID, + ); + } + + /** + * Allow auto-paginating iteration on an unawaited list call, eg: + * + * for await (const item of client.items.list()) { + * console.log(item) + * } + */ + async *[Symbol.asyncIterator]() { + const page = await this; + for await (const item of page) { + yield item; + } + } +} export interface PageResponse { data: Array; @@ -16,7 +126,7 @@ export class Page extends AbstractPage implements PageResponse object: string; - constructor(client: APIClient, response: Response, body: PageResponse, options: FinalRequestOptions) { + constructor(client: OpenAI, response: Response, body: PageResponse, options: FinalRequestOptions) { super(client, response, body, options); this.data = body.data || []; @@ -27,22 +137,15 @@ export class Page extends AbstractPage implements PageResponse return this.data ?? []; } - // @deprecated Please use `nextPageInfo()` instead - /** - * This page represents a response that isn't actually paginated at the API level - * so there will never be any next page params. - */ - nextPageParams(): null { - return null; - } - - nextPageInfo(): null { + nextPageRequestOptions(): PageRequestOptions | null { return null; } } export interface CursorPageResponse { data: Array; + + has_more: boolean; } export interface CursorPageParams { @@ -57,8 +160,10 @@ export class CursorPage { data: Array; + has_more: boolean; + constructor( - client: APIClient, + client: OpenAI, response: Response, body: CursorPageResponse, options: FinalRequestOptions, @@ -66,33 +171,34 @@ export class CursorPage super(client, response, body, options); this.data = body.data || []; + this.has_more = body.has_more || false; } getPaginatedItems(): Item[] { return this.data ?? []; } - // @deprecated Please use `nextPageInfo()` instead - nextPageParams(): Partial | null { - const info = this.nextPageInfo(); - if (!info) return null; - if ('params' in info) return info.params; - const params = Object.fromEntries(info.url.searchParams); - if (!Object.keys(params).length) return null; - return params; + override hasNextPage(): boolean { + if (this.has_more === false) { + return false; + } + + return super.hasNextPage(); } - nextPageInfo(): PageInfo | null { + nextPageRequestOptions(): PageRequestOptions | null { const data = this.getPaginatedItems(); - if (!data.length) { - return null; - } - const id = data[data.length - 1]?.id; if (!id) { return null; } - return { params: { after: id } }; + return { + ...this.options, + query: { + ...maybeObj(this.options.query), + after: id, + }, + }; } } diff --git a/src/resource.ts b/src/resource.ts index 87847c879..ea299e176 100644 --- a/src/resource.ts +++ b/src/resource.ts @@ -1,6 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import type { OpenAI } from './index'; +import type { OpenAI } from './client'; export class APIResource { protected _client: OpenAI; diff --git a/src/resources/audio/speech.ts b/src/resources/audio/speech.ts index 1cda80f79..81dc3e47d 100644 --- a/src/resources/audio/speech.ts +++ b/src/resources/audio/speech.ts @@ -1,15 +1,21 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import { APIResource } from '../../resource'; -import * as Core from '../../core'; -import { type Response } from '../../_shims/index'; +import { APIPromise } from '../../api-promise'; +import { buildHeaders } from '../../internal/headers'; +import { RequestOptions } from '../../internal/request-options'; export class Speech extends APIResource { /** * Generates audio from the input text. */ - create(body: SpeechCreateParams, options?: Core.RequestOptions): Core.APIPromise { - return this._client.post('/audio/speech', { body, ...options, __binaryResponse: true }); + create(body: SpeechCreateParams, options?: RequestOptions): APIPromise { + return this._client.post('/audio/speech', { + body, + ...options, + headers: buildHeaders([{ Accept: 'application/octet-stream' }, options?.headers]), + __binaryResponse: true, + }); } } @@ -28,12 +34,12 @@ export interface SpeechCreateParams { model: (string & {}) | SpeechModel; /** - * The voice to use when generating the audio. Supported voices are `alloy`, - * `echo`, `fable`, `onyx`, `nova`, and `shimmer`. Previews of the voices are - * available in the + * The voice to use when generating the audio. Supported voices are `alloy`, `ash`, + * `coral`, `echo`, `fable`, `onyx`, `nova`, `sage` and `shimmer`. Previews of the + * voices are available in the * [Text to speech guide](https://platform.openai.com/docs/guides/text-to-speech#voice-options). */ - voice: 'alloy' | 'echo' | 'fable' | 'onyx' | 'nova' | 'shimmer'; + voice: 'alloy' | 'ash' | 'coral' | 'echo' | 'fable' | 'onyx' | 'nova' | 'sage' | 'shimmer'; /** * The format to audio in. Supported formats are `mp3`, `opus`, `aac`, `flac`, diff --git a/src/resources/audio/transcriptions.ts b/src/resources/audio/transcriptions.ts index 0b6da4620..253bd1e40 100644 --- a/src/resources/audio/transcriptions.ts +++ b/src/resources/audio/transcriptions.ts @@ -1,8 +1,11 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import { APIResource } from '../../resource'; -import * as Core from '../../core'; import * as AudioAPI from './audio'; +import { APIPromise } from '../../api-promise'; +import { type Uploadable } from '../../uploads'; +import { RequestOptions } from '../../internal/request-options'; +import { multipartFormRequestOptions } from '../../internal/uploads'; export class Transcriptions extends APIResource { /** @@ -10,22 +13,25 @@ export class Transcriptions extends APIResource { */ create( body: TranscriptionCreateParams<'json' | undefined>, - options?: Core.RequestOptions, - ): Core.APIPromise; + options?: RequestOptions, + ): APIPromise; create( body: TranscriptionCreateParams<'verbose_json'>, - options?: Core.RequestOptions, - ): Core.APIPromise; + options?: RequestOptions, + ): APIPromise; create( body: TranscriptionCreateParams<'srt' | 'vtt' | 'text'>, - options?: Core.RequestOptions, - ): Core.APIPromise; - create(body: TranscriptionCreateParams, options?: Core.RequestOptions): Core.APIPromise; + options?: RequestOptions, + ): APIPromise; + create(body: TranscriptionCreateParams, options?: RequestOptions): APIPromise; create( body: TranscriptionCreateParams, - options?: Core.RequestOptions, - ): Core.APIPromise { - return this._client.post('/audio/transcriptions', Core.multipartFormRequestOptions({ body, ...options })); + options?: RequestOptions, + ): APIPromise { + return this._client.post( + '/audio/transcriptions', + multipartFormRequestOptions({ body, ...options, __metadata: { model: body.model } }, this._client), + ); } } @@ -103,7 +109,7 @@ export interface TranscriptionVerbose { /** * The duration of the input audio. */ - duration: string; + duration: number; /** * The language of the input audio. @@ -156,7 +162,7 @@ export interface TranscriptionCreateParams< * The audio file object (not file name) to transcribe, in one of these formats: * flac, mp3, mp4, mpeg, mpga, m4a, ogg, wav, or webm. */ - file: Core.Uploadable; + file: Uploadable; /** * ID of the model to use. Only `whisper-1` (which is powered by our open source @@ -166,8 +172,8 @@ export interface TranscriptionCreateParams< /** * The language of the input audio. Supplying the input language in - * [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) format will - * improve accuracy and latency. + * [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) + * format will improve accuracy and latency. */ language?: string; diff --git a/src/resources/audio/translations.ts b/src/resources/audio/translations.ts index c6bf7c870..4c309e441 100644 --- a/src/resources/audio/translations.ts +++ b/src/resources/audio/translations.ts @@ -1,9 +1,12 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import { APIResource } from '../../resource'; -import * as Core from '../../core'; import * as AudioAPI from './audio'; import * as TranscriptionsAPI from './transcriptions'; +import { APIPromise } from '../../api-promise'; +import { type Uploadable } from '../../uploads'; +import { RequestOptions } from '../../internal/request-options'; +import { multipartFormRequestOptions } from '../../internal/uploads'; export class Translations extends APIResource { /** @@ -11,22 +14,22 @@ export class Translations extends APIResource { */ create( body: TranslationCreateParams<'json' | undefined>, - options?: Core.RequestOptions, - ): Core.APIPromise; + options?: RequestOptions, + ): APIPromise; create( body: TranslationCreateParams<'verbose_json'>, - options?: Core.RequestOptions, - ): Core.APIPromise; - create( - body: TranslationCreateParams<'text' | 'srt' | 'vtt'>, - options?: Core.RequestOptions, - ): Core.APIPromise; - create(body: TranslationCreateParams, options?: Core.RequestOptions): Core.APIPromise; + options?: RequestOptions, + ): APIPromise; + create(body: TranslationCreateParams<'text' | 'srt' | 'vtt'>, options?: RequestOptions): APIPromise; + create(body: TranslationCreateParams, options?: RequestOptions): APIPromise; create( body: TranslationCreateParams, - options?: Core.RequestOptions, - ): Core.APIPromise { - return this._client.post('/audio/translations', Core.multipartFormRequestOptions({ body, ...options })); + options?: RequestOptions, + ): APIPromise { + return this._client.post( + '/audio/translations', + multipartFormRequestOptions({ body, ...options, __metadata: { model: body.model } }, this._client), + ); } } @@ -38,7 +41,7 @@ export interface TranslationVerbose { /** * The duration of the input audio. */ - duration: string; + duration: number; /** * The language of the output translation (always `english`). @@ -65,7 +68,7 @@ export interface TranslationCreateParams< * The audio file object (not file name) translate, in one of these formats: flac, * mp3, mp4, mpeg, mpga, m4a, ogg, wav, or webm. */ - file: Core.Uploadable; + file: Uploadable; /** * ID of the model to use. Only `whisper-1` (which is powered by our open source diff --git a/src/resources/batches.ts b/src/resources/batches.ts index ec5ca6331..db32d782b 100644 --- a/src/resources/batches.ts +++ b/src/resources/batches.ts @@ -1,39 +1,36 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import { APIResource } from '../resource'; -import { isRequestOptions } from '../core'; -import * as Core from '../core'; import * as BatchesAPI from './batches'; -import { CursorPage, type CursorPageParams } from '../pagination'; +import * as Shared from './shared'; +import { APIPromise } from '../api-promise'; +import { CursorPage, type CursorPageParams, PagePromise } from '../pagination'; +import { RequestOptions } from '../internal/request-options'; +import { path } from '../internal/utils/path'; export class Batches extends APIResource { /** * Creates and executes a batch from an uploaded file of requests */ - create(body: BatchCreateParams, options?: Core.RequestOptions): Core.APIPromise { + create(body: BatchCreateParams, options?: RequestOptions): APIPromise { return this._client.post('/batches', { body, ...options }); } /** * Retrieves a batch. */ - retrieve(batchId: string, options?: Core.RequestOptions): Core.APIPromise { - return this._client.get(`/batches/${batchId}`, options); + retrieve(batchID: string, options?: RequestOptions): APIPromise { + return this._client.get(path`/batches/${batchID}`, options); } /** * List your organization's batches. */ - list(query?: BatchListParams, options?: Core.RequestOptions): Core.PagePromise; - list(options?: Core.RequestOptions): Core.PagePromise; list( - query: BatchListParams | Core.RequestOptions = {}, - options?: Core.RequestOptions, - ): Core.PagePromise { - if (isRequestOptions(query)) { - return this.list({}, query); - } - return this._client.getAPIList('/batches', BatchesPage, { query, ...options }); + query: BatchListParams | null | undefined = {}, + options?: RequestOptions, + ): PagePromise { + return this._client.getAPIList('/batches', CursorPage, { query, ...options }); } /** @@ -41,12 +38,12 @@ export class Batches extends APIResource { * 10 minutes, before changing to `cancelled`, where it will have partial results * (if any) available in the output file. */ - cancel(batchId: string, options?: Core.RequestOptions): Core.APIPromise { - return this._client.post(`/batches/${batchId}/cancel`, options); + cancel(batchID: string, options?: RequestOptions): APIPromise { + return this._client.post(path`/batches/${batchID}/cancel`, options); } } -export class BatchesPage extends CursorPage {} +export type BatchesPage = CursorPage; export interface Batch { id: string; @@ -138,11 +135,13 @@ export interface Batch { /** * Set of 16 key-value pairs that can be attached to an object. This can be useful - * for storing additional information about the object in a structured format. Keys - * can be a maximum of 64 characters long and values can be a maxium of 512 - * characters long. + * for storing additional information about the object in a structured format, and + * querying for objects via API or the dashboard. + * + * Keys are strings with a maximum length of 64 characters. Values are strings with + * a maximum length of 512 characters. */ - metadata?: unknown | null; + metadata?: Shared.Metadata | null; /** * The ID of the file containing the outputs of successfully executed requests. @@ -237,21 +236,24 @@ export interface BatchCreateParams { input_file_id: string; /** - * Optional custom metadata for the batch. + * Set of 16 key-value pairs that can be attached to an object. This can be useful + * for storing additional information about the object in a structured format, and + * querying for objects via API or the dashboard. + * + * Keys are strings with a maximum length of 64 characters. Values are strings with + * a maximum length of 512 characters. */ - metadata?: Record | null; + metadata?: Shared.Metadata | null; } export interface BatchListParams extends CursorPageParams {} -Batches.BatchesPage = BatchesPage; - export declare namespace Batches { export { type Batch as Batch, type BatchError as BatchError, type BatchRequestCounts as BatchRequestCounts, - BatchesPage as BatchesPage, + type BatchesPage as BatchesPage, type BatchCreateParams as BatchCreateParams, type BatchListParams as BatchListParams, }; diff --git a/src/resources/beta/assistants.ts b/src/resources/beta/assistants.ts index 0e657b1d4..0e109deed 100644 --- a/src/resources/beta/assistants.ts +++ b/src/resources/beta/assistants.ts @@ -1,8 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import { APIResource } from '../../resource'; -import { isRequestOptions } from '../../core'; -import * as Core from '../../core'; import * as Shared from '../shared'; import * as ChatAPI from '../chat/chat'; import * as MessagesAPI from './threads/messages'; @@ -10,42 +8,42 @@ import * as ThreadsAPI from './threads/threads'; import * as VectorStoresAPI from './vector-stores/vector-stores'; import * as RunsAPI from './threads/runs/runs'; import * as StepsAPI from './threads/runs/steps'; -import { CursorPage, type CursorPageParams } from '../../pagination'; +import { APIPromise } from '../../api-promise'; +import { CursorPage, type CursorPageParams, PagePromise } from '../../pagination'; +import { buildHeaders } from '../../internal/headers'; +import { RequestOptions } from '../../internal/request-options'; +import { path } from '../../internal/utils/path'; export class Assistants extends APIResource { /** * Create an assistant with a model and instructions. */ - create(body: AssistantCreateParams, options?: Core.RequestOptions): Core.APIPromise { + create(body: AssistantCreateParams, options?: RequestOptions): APIPromise { return this._client.post('/assistants', { body, ...options, - headers: { 'OpenAI-Beta': 'assistants=v2', ...options?.headers }, + headers: buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), }); } /** * Retrieves an assistant. */ - retrieve(assistantId: string, options?: Core.RequestOptions): Core.APIPromise { - return this._client.get(`/assistants/${assistantId}`, { + retrieve(assistantID: string, options?: RequestOptions): APIPromise { + return this._client.get(path`/assistants/${assistantID}`, { ...options, - headers: { 'OpenAI-Beta': 'assistants=v2', ...options?.headers }, + headers: buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), }); } /** * Modifies an assistant. */ - update( - assistantId: string, - body: AssistantUpdateParams, - options?: Core.RequestOptions, - ): Core.APIPromise { - return this._client.post(`/assistants/${assistantId}`, { + update(assistantID: string, body: AssistantUpdateParams, options?: RequestOptions): APIPromise { + return this._client.post(path`/assistants/${assistantID}`, { body, ...options, - headers: { 'OpenAI-Beta': 'assistants=v2', ...options?.headers }, + headers: buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), }); } @@ -53,36 +51,28 @@ export class Assistants extends APIResource { * Returns a list of assistants. */ list( - query?: AssistantListParams, - options?: Core.RequestOptions, - ): Core.PagePromise; - list(options?: Core.RequestOptions): Core.PagePromise; - list( - query: AssistantListParams | Core.RequestOptions = {}, - options?: Core.RequestOptions, - ): Core.PagePromise { - if (isRequestOptions(query)) { - return this.list({}, query); - } - return this._client.getAPIList('/assistants', AssistantsPage, { + query: AssistantListParams | null | undefined = {}, + options?: RequestOptions, + ): PagePromise { + return this._client.getAPIList('/assistants', CursorPage, { query, ...options, - headers: { 'OpenAI-Beta': 'assistants=v2', ...options?.headers }, + headers: buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), }); } /** * Delete an assistant. */ - del(assistantId: string, options?: Core.RequestOptions): Core.APIPromise { - return this._client.delete(`/assistants/${assistantId}`, { + delete(assistantID: string, options?: RequestOptions): APIPromise { + return this._client.delete(path`/assistants/${assistantID}`, { ...options, - headers: { 'OpenAI-Beta': 'assistants=v2', ...options?.headers }, + headers: buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), }); } } -export class AssistantsPage extends CursorPage {} +export type AssistantsPage = CursorPage; /** * Represents an `assistant` that can call the model and use tools. @@ -111,11 +101,13 @@ export interface Assistant { /** * Set of 16 key-value pairs that can be attached to an object. This can be useful - * for storing additional information about the object in a structured format. Keys - * can be a maximum of 64 characters long and values can be a maxium of 512 - * characters long. + * for storing additional information about the object in a structured format, and + * querying for objects via API or the dashboard. + * + * Keys are strings with a maximum length of 64 characters. Values are strings with + * a maximum length of 512 characters. */ - metadata: unknown | null; + metadata: Shared.Metadata | null; /** * ID of the model to use. You can use the @@ -1118,17 +1110,29 @@ export interface AssistantCreateParams { /** * Set of 16 key-value pairs that can be attached to an object. This can be useful - * for storing additional information about the object in a structured format. Keys - * can be a maximum of 64 characters long and values can be a maxium of 512 - * characters long. + * for storing additional information about the object in a structured format, and + * querying for objects via API or the dashboard. + * + * Keys are strings with a maximum length of 64 characters. Values are strings with + * a maximum length of 512 characters. */ - metadata?: unknown | null; + metadata?: Shared.Metadata | null; /** * The name of the assistant. The maximum length is 256 characters. */ name?: string | null; + /** + * **o1 and o3-mini models only** + * + * Constrains effort on reasoning for + * [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently + * supported values are `low`, `medium`, and `high`. Reducing reasoning effort can + * result in faster responses and fewer tokens used on reasoning in a response. + */ + reasoning_effort?: 'low' | 'medium' | 'high' | null; + /** * Specifies the format that the model must output. Compatible with * [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), @@ -1242,12 +1246,14 @@ export namespace AssistantCreateParams { file_ids?: Array; /** - * Set of 16 key-value pairs that can be attached to a vector store. This can be - * useful for storing additional information about the vector store in a structured - * format. Keys can be a maximum of 64 characters long and values can be a maxium - * of 512 characters long. + * Set of 16 key-value pairs that can be attached to an object. This can be useful + * for storing additional information about the object in a structured format, and + * querying for objects via API or the dashboard. + * + * Keys are strings with a maximum length of 64 characters. Values are strings with + * a maximum length of 512 characters. */ - metadata?: unknown; + metadata?: Shared.Metadata | null; } } } @@ -1267,11 +1273,13 @@ export interface AssistantUpdateParams { /** * Set of 16 key-value pairs that can be attached to an object. This can be useful - * for storing additional information about the object in a structured format. Keys - * can be a maximum of 64 characters long and values can be a maxium of 512 - * characters long. + * for storing additional information about the object in a structured format, and + * querying for objects via API or the dashboard. + * + * Keys are strings with a maximum length of 64 characters. Values are strings with + * a maximum length of 512 characters. */ - metadata?: unknown | null; + metadata?: Shared.Metadata | null; /** * ID of the model to use. You can use the @@ -1280,13 +1288,54 @@ export interface AssistantUpdateParams { * [Model overview](https://platform.openai.com/docs/models) for descriptions of * them. */ - model?: string; + model?: + | (string & {}) + | 'o3-mini' + | 'o3-mini-2025-01-31' + | 'o1' + | 'o1-2024-12-17' + | 'gpt-4o' + | 'gpt-4o-2024-11-20' + | 'gpt-4o-2024-08-06' + | 'gpt-4o-2024-05-13' + | 'gpt-4o-mini' + | 'gpt-4o-mini-2024-07-18' + | 'gpt-4.5-preview' + | 'gpt-4.5-preview-2025-02-27' + | 'gpt-4-turbo' + | 'gpt-4-turbo-2024-04-09' + | 'gpt-4-0125-preview' + | 'gpt-4-turbo-preview' + | 'gpt-4-1106-preview' + | 'gpt-4-vision-preview' + | 'gpt-4' + | 'gpt-4-0314' + | 'gpt-4-0613' + | 'gpt-4-32k' + | 'gpt-4-32k-0314' + | 'gpt-4-32k-0613' + | 'gpt-3.5-turbo' + | 'gpt-3.5-turbo-16k' + | 'gpt-3.5-turbo-0613' + | 'gpt-3.5-turbo-1106' + | 'gpt-3.5-turbo-0125' + | 'gpt-3.5-turbo-16k-0613'; /** * The name of the assistant. The maximum length is 256 characters. */ name?: string | null; + /** + * **o1 and o3-mini models only** + * + * Constrains effort on reasoning for + * [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently + * supported values are `low`, `medium`, and `high`. Reducing reasoning effort can + * result in faster responses and fewer tokens used on reasoning in a response. + */ + reasoning_effort?: 'low' | 'medium' | 'high' | null; + /** * Specifies the format that the model must output. Compatible with * [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), @@ -1395,8 +1444,6 @@ export interface AssistantListParams extends CursorPageParams { order?: 'asc' | 'desc'; } -Assistants.AssistantsPage = AssistantsPage; - export declare namespace Assistants { export { type Assistant as Assistant, @@ -1410,7 +1457,7 @@ export declare namespace Assistants { type RunStepStreamEvent as RunStepStreamEvent, type RunStreamEvent as RunStreamEvent, type ThreadStreamEvent as ThreadStreamEvent, - AssistantsPage as AssistantsPage, + type AssistantsPage as AssistantsPage, type AssistantCreateParams as AssistantCreateParams, type AssistantUpdateParams as AssistantUpdateParams, type AssistantListParams as AssistantListParams, diff --git a/src/resources/beta/beta.ts b/src/resources/beta/beta.ts index b904abe4a..beab540c5 100644 --- a/src/resources/beta/beta.ts +++ b/src/resources/beta/beta.ts @@ -21,6 +21,8 @@ import { RunStreamEvent, ThreadStreamEvent, } from './assistants'; +import * as RealtimeAPI from './realtime/realtime'; +import { Realtime } from './realtime/realtime'; import * as ThreadsAPI from './threads/threads'; import { AssistantResponseFormatOption, @@ -46,7 +48,7 @@ import { OtherFileChunkingStrategyObject, StaticFileChunkingStrategy, StaticFileChunkingStrategyObject, - StaticFileChunkingStrategyParam, + StaticFileChunkingStrategyObjectParam, VectorStore, VectorStoreCreateParams, VectorStoreDeleted, @@ -58,19 +60,21 @@ import { import { Chat } from './chat/chat'; export class Beta extends APIResource { + realtime: RealtimeAPI.Realtime = new RealtimeAPI.Realtime(this._client); vectorStores: VectorStoresAPI.VectorStores = new VectorStoresAPI.VectorStores(this._client); chat: ChatAPI.Chat = new ChatAPI.Chat(this._client); assistants: AssistantsAPI.Assistants = new AssistantsAPI.Assistants(this._client); threads: ThreadsAPI.Threads = new ThreadsAPI.Threads(this._client); } +Beta.Realtime = Realtime; Beta.VectorStores = VectorStores; -Beta.VectorStoresPage = VectorStoresPage; Beta.Assistants = Assistants; -Beta.AssistantsPage = AssistantsPage; Beta.Threads = Threads; export declare namespace Beta { + export { Realtime as Realtime }; + export { VectorStores as VectorStores, type AutoFileChunkingStrategyParam as AutoFileChunkingStrategyParam, @@ -79,10 +83,10 @@ export declare namespace Beta { type OtherFileChunkingStrategyObject as OtherFileChunkingStrategyObject, type StaticFileChunkingStrategy as StaticFileChunkingStrategy, type StaticFileChunkingStrategyObject as StaticFileChunkingStrategyObject, - type StaticFileChunkingStrategyParam as StaticFileChunkingStrategyParam, + type StaticFileChunkingStrategyObjectParam as StaticFileChunkingStrategyObjectParam, type VectorStore as VectorStore, type VectorStoreDeleted as VectorStoreDeleted, - VectorStoresPage as VectorStoresPage, + type VectorStoresPage as VectorStoresPage, type VectorStoreCreateParams as VectorStoreCreateParams, type VectorStoreUpdateParams as VectorStoreUpdateParams, type VectorStoreListParams as VectorStoreListParams, @@ -103,7 +107,7 @@ export declare namespace Beta { type RunStepStreamEvent as RunStepStreamEvent, type RunStreamEvent as RunStreamEvent, type ThreadStreamEvent as ThreadStreamEvent, - AssistantsPage as AssistantsPage, + type AssistantsPage as AssistantsPage, type AssistantCreateParams as AssistantCreateParams, type AssistantUpdateParams as AssistantUpdateParams, type AssistantListParams as AssistantListParams, diff --git a/src/resources/beta/chat/completions.ts b/src/resources/beta/chat/completions.ts index c9360a95c..b2e0148bd 100644 --- a/src/resources/beta/chat/completions.ts +++ b/src/resources/beta/chat/completions.ts @@ -1,14 +1,8 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import * as Core from '../../../core'; import { APIResource } from '../../../resource'; -import { ChatCompletionRunner, ChatCompletionFunctionRunnerParams } from '../../../lib/ChatCompletionRunner'; -import { - ChatCompletionStreamingRunner, - ChatCompletionStreamingFunctionRunnerParams, -} from '../../../lib/ChatCompletionStreamingRunner'; -import { BaseFunctionsArgs } from '../../../lib/RunnableFunction'; -import { RunnerOptions } from '../../../lib/AbstractChatCompletionRunner'; +import { ChatCompletionRunner } from '../../../lib/ChatCompletionRunner'; +import { ChatCompletionStreamingRunner } from '../../../lib/ChatCompletionStreamingRunner'; import { ChatCompletionToolRunnerParams } from '../../../lib/ChatCompletionRunner'; import { ChatCompletionStreamingToolRunnerParams } from '../../../lib/ChatCompletionStreamingRunner'; import { ChatCompletionStream, type ChatCompletionStreamParams } from '../../../lib/ChatCompletionStream'; @@ -19,26 +13,21 @@ import { ChatCompletionMessageToolCall, } from '../../chat/completions'; import { ExtractParsedContentFromParams, parseChatCompletion, validateInputTools } from '../../../lib/parser'; +import { RequestOptions } from '../../../internal/request-options'; +import { type APIPromise } from '../../../api-promise'; +import { RunnerOptions } from '../../../lib/AbstractChatCompletionRunner'; -export { - ChatCompletionStreamingRunner, - type ChatCompletionStreamingFunctionRunnerParams, -} from '../../../lib/ChatCompletionStreamingRunner'; +export { ChatCompletionStream, type ChatCompletionStreamParams } from '../../../lib/ChatCompletionStream'; +export { ChatCompletionRunner } from '../../../lib/ChatCompletionRunner'; +export { ChatCompletionStreamingRunner } from '../../../lib/ChatCompletionStreamingRunner'; export { type RunnableFunction, - type RunnableFunctions, type RunnableFunctionWithParse, type RunnableFunctionWithoutParse, - ParsingFunction, ParsingToolFunction, } from '../../../lib/RunnableFunction'; export { type ChatCompletionToolRunnerParams } from '../../../lib/ChatCompletionRunner'; export { type ChatCompletionStreamingToolRunnerParams } from '../../../lib/ChatCompletionStreamingRunner'; -export { ChatCompletionStream, type ChatCompletionStreamParams } from '../../../lib/ChatCompletionStream'; -export { - ChatCompletionRunner, - type ChatCompletionFunctionRunnerParams, -} from '../../../lib/ChatCompletionRunner'; export interface ParsedFunction extends ChatCompletionMessageToolCall.Function { parsed_arguments?: unknown; @@ -50,7 +39,7 @@ export interface ParsedFunctionToolCall extends ChatCompletionMessageToolCall { export interface ParsedChatCompletionMessage extends ChatCompletionMessage { parsed: ParsedT | null; - tool_calls: Array; + tool_calls?: Array; } export interface ParsedChoice extends ChatCompletion.Choice { @@ -66,8 +55,8 @@ export type ChatCompletionParseParams = ChatCompletionCreateParamsNonStreaming; export class Completions extends APIResource { parse>( body: Params, - options?: Core.RequestOptions, - ): Core.APIPromise> { + options?: RequestOptions, + ): APIPromise> { validateInputTools(body.tools); return this._client.chat.completions @@ -81,37 +70,6 @@ export class Completions extends APIResource { ._thenUnwrap((completion) => parseChatCompletion(completion, body)); } - /** - * @deprecated - use `runTools` instead. - */ - runFunctions( - body: ChatCompletionFunctionRunnerParams, - options?: Core.RequestOptions, - ): ChatCompletionRunner; - runFunctions( - body: ChatCompletionStreamingFunctionRunnerParams, - options?: Core.RequestOptions, - ): ChatCompletionStreamingRunner; - runFunctions( - body: - | ChatCompletionFunctionRunnerParams - | ChatCompletionStreamingFunctionRunnerParams, - options?: Core.RequestOptions, - ): ChatCompletionRunner | ChatCompletionStreamingRunner { - if (body.stream) { - return ChatCompletionStreamingRunner.runFunctions( - this._client, - body as ChatCompletionStreamingFunctionRunnerParams, - options, - ); - } - return ChatCompletionRunner.runFunctions( - this._client, - body as ChatCompletionFunctionRunnerParams, - options, - ); - } - /** * A convenience helper for using tool calls with the /chat/completions endpoint * which automatically calls the JavaScript functions you provide and sends their @@ -154,7 +112,7 @@ export class Completions extends APIResource { */ stream>( body: Params, - options?: Core.RequestOptions, + options?: RequestOptions, ): ChatCompletionStream { return ChatCompletionStream.createChatCompletion(this._client, body, options); } diff --git a/src/resources/beta/index.ts b/src/resources/beta/index.ts index d7111288f..cedb1791a 100644 --- a/src/resources/beta/index.ts +++ b/src/resources/beta/index.ts @@ -1,7 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. export { - AssistantsPage, Assistants, type Assistant, type AssistantDeleted, @@ -17,8 +16,10 @@ export { type AssistantCreateParams, type AssistantUpdateParams, type AssistantListParams, + type AssistantsPage, } from './assistants'; export { Beta } from './beta'; +export { Realtime } from './realtime/index'; export { Chat } from './chat/index'; export { Threads, @@ -37,7 +38,6 @@ export { type ThreadCreateAndRunStreamParams, } from './threads/index'; export { - VectorStoresPage, VectorStores, type AutoFileChunkingStrategyParam, type FileChunkingStrategy, @@ -45,10 +45,11 @@ export { type OtherFileChunkingStrategyObject, type StaticFileChunkingStrategy, type StaticFileChunkingStrategyObject, - type StaticFileChunkingStrategyParam, + type StaticFileChunkingStrategyObjectParam, type VectorStore, type VectorStoreDeleted, type VectorStoreCreateParams, type VectorStoreUpdateParams, type VectorStoreListParams, + type VectorStoresPage, } from './vector-stores/index'; diff --git a/src/resources/beta/realtime/index.ts b/src/resources/beta/realtime/index.ts new file mode 100644 index 000000000..66c3ecaae --- /dev/null +++ b/src/resources/beta/realtime/index.ts @@ -0,0 +1,4 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export { Realtime } from './realtime'; +export { Sessions, type Session, type SessionCreateResponse, type SessionCreateParams } from './sessions'; diff --git a/src/resources/beta/realtime/realtime.ts b/src/resources/beta/realtime/realtime.ts new file mode 100644 index 000000000..5e2b1c833 --- /dev/null +++ b/src/resources/beta/realtime/realtime.ts @@ -0,0 +1,2058 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../../../resource'; +import * as RealtimeAPI from './realtime'; +import * as Shared from '../../shared'; +import * as SessionsAPI from './sessions'; +import { + Session as SessionsAPISession, + SessionCreateParams, + SessionCreateResponse, + Sessions, +} from './sessions'; + +export class Realtime extends APIResource { + sessions: SessionsAPI.Sessions = new SessionsAPI.Sessions(this._client); +} + +/** + * Returned when a conversation is created. Emitted right after session creation. + */ +export interface ConversationCreatedEvent { + /** + * The conversation resource. + */ + conversation: ConversationCreatedEvent.Conversation; + + /** + * The unique ID of the server event. + */ + event_id: string; + + /** + * The event type, must be `conversation.created`. + */ + type: 'conversation.created'; +} + +export namespace ConversationCreatedEvent { + /** + * The conversation resource. + */ + export interface Conversation { + /** + * The unique ID of the conversation. + */ + id?: string; + + /** + * The object type, must be `realtime.conversation`. + */ + object?: 'realtime.conversation'; + } +} + +/** + * The item to add to the conversation. + */ +export interface ConversationItem { + /** + * The unique ID of the item, this can be generated by the client to help manage + * server-side context, but is not required because the server will generate one if + * not provided. + */ + id?: string; + + /** + * The arguments of the function call (for `function_call` items). + */ + arguments?: string; + + /** + * The ID of the function call (for `function_call` and `function_call_output` + * items). If passed on a `function_call_output` item, the server will check that a + * `function_call` item with the same ID exists in the conversation history. + */ + call_id?: string; + + /** + * The content of the message, applicable for `message` items. + * + * - Message items of role `system` support only `input_text` content + * - Message items of role `user` support `input_text` and `input_audio` content + * - Message items of role `assistant` support `text` content. + */ + content?: Array; + + /** + * The name of the function being called (for `function_call` items). + */ + name?: string; + + /** + * Identifier for the API object being returned - always `realtime.item`. + */ + object?: 'realtime.item'; + + /** + * The output of the function call (for `function_call_output` items). + */ + output?: string; + + /** + * The role of the message sender (`user`, `assistant`, `system`), only applicable + * for `message` items. + */ + role?: 'user' | 'assistant' | 'system'; + + /** + * The status of the item (`completed`, `incomplete`). These have no effect on the + * conversation, but are accepted for consistency with the + * `conversation.item.created` event. + */ + status?: 'completed' | 'incomplete'; + + /** + * The type of the item (`message`, `function_call`, `function_call_output`). + */ + type?: 'message' | 'function_call' | 'function_call_output'; +} + +export interface ConversationItemContent { + /** + * ID of a previous conversation item to reference (for `item_reference` content + * types in `response.create` events). These can reference both client and server + * created items. + */ + id?: string; + + /** + * Base64-encoded audio bytes, used for `input_audio` content type. + */ + audio?: string; + + /** + * The text content, used for `input_text` and `text` content types. + */ + text?: string; + + /** + * The transcript of the audio, used for `input_audio` content type. + */ + transcript?: string; + + /** + * The content type (`input_text`, `input_audio`, `item_reference`, `text`). + */ + type?: 'input_text' | 'input_audio' | 'item_reference' | 'text'; +} + +/** + * Add a new Item to the Conversation's context, including messages, function + * calls, and function call responses. This event can be used both to populate a + * "history" of the conversation and to add new items mid-stream, but has the + * current limitation that it cannot populate assistant audio messages. + * + * If successful, the server will respond with a `conversation.item.created` event, + * otherwise an `error` event will be sent. + */ +export interface ConversationItemCreateEvent { + /** + * The item to add to the conversation. + */ + item: ConversationItem; + + /** + * The event type, must be `conversation.item.create`. + */ + type: 'conversation.item.create'; + + /** + * Optional client-generated ID used to identify this event. + */ + event_id?: string; + + /** + * The ID of the preceding item after which the new item will be inserted. If not + * set, the new item will be appended to the end of the conversation. If set to + * `root`, the new item will be added to the beginning of the conversation. If set + * to an existing ID, it allows an item to be inserted mid-conversation. If the ID + * cannot be found, an error will be returned and the item will not be added. + */ + previous_item_id?: string; +} + +/** + * Returned when a conversation item is created. There are several scenarios that + * produce this event: + * + * - The server is generating a Response, which if successful will produce either + * one or two Items, which will be of type `message` (role `assistant`) or type + * `function_call`. + * - The input audio buffer has been committed, either by the client or the server + * (in `server_vad` mode). The server will take the content of the input audio + * buffer and add it to a new user message Item. + * - The client has sent a `conversation.item.create` event to add a new Item to + * the Conversation. + */ +export interface ConversationItemCreatedEvent { + /** + * The unique ID of the server event. + */ + event_id: string; + + /** + * The item to add to the conversation. + */ + item: ConversationItem; + + /** + * The ID of the preceding item in the Conversation context, allows the client to + * understand the order of the conversation. + */ + previous_item_id: string; + + /** + * The event type, must be `conversation.item.created`. + */ + type: 'conversation.item.created'; +} + +/** + * Send this event when you want to remove any item from the conversation history. + * The server will respond with a `conversation.item.deleted` event, unless the + * item does not exist in the conversation history, in which case the server will + * respond with an error. + */ +export interface ConversationItemDeleteEvent { + /** + * The ID of the item to delete. + */ + item_id: string; + + /** + * The event type, must be `conversation.item.delete`. + */ + type: 'conversation.item.delete'; + + /** + * Optional client-generated ID used to identify this event. + */ + event_id?: string; +} + +/** + * Returned when an item in the conversation is deleted by the client with a + * `conversation.item.delete` event. This event is used to synchronize the server's + * understanding of the conversation history with the client's view. + */ +export interface ConversationItemDeletedEvent { + /** + * The unique ID of the server event. + */ + event_id: string; + + /** + * The ID of the item that was deleted. + */ + item_id: string; + + /** + * The event type, must be `conversation.item.deleted`. + */ + type: 'conversation.item.deleted'; +} + +/** + * This event is the output of audio transcription for user audio written to the + * user audio buffer. Transcription begins when the input audio buffer is committed + * by the client or server (in `server_vad` mode). Transcription runs + * asynchronously with Response creation, so this event may come before or after + * the Response events. + * + * Realtime API models accept audio natively, and thus input transcription is a + * separate process run on a separate ASR (Automatic Speech Recognition) model, + * currently always `whisper-1`. Thus the transcript may diverge somewhat from the + * model's interpretation, and should be treated as a rough guide. + */ +export interface ConversationItemInputAudioTranscriptionCompletedEvent { + /** + * The index of the content part containing the audio. + */ + content_index: number; + + /** + * The unique ID of the server event. + */ + event_id: string; + + /** + * The ID of the user message item containing the audio. + */ + item_id: string; + + /** + * The transcribed text. + */ + transcript: string; + + /** + * The event type, must be `conversation.item.input_audio_transcription.completed`. + */ + type: 'conversation.item.input_audio_transcription.completed'; +} + +/** + * Returned when input audio transcription is configured, and a transcription + * request for a user message failed. These events are separate from other `error` + * events so that the client can identify the related Item. + */ +export interface ConversationItemInputAudioTranscriptionFailedEvent { + /** + * The index of the content part containing the audio. + */ + content_index: number; + + /** + * Details of the transcription error. + */ + error: ConversationItemInputAudioTranscriptionFailedEvent.Error; + + /** + * The unique ID of the server event. + */ + event_id: string; + + /** + * The ID of the user message item. + */ + item_id: string; + + /** + * The event type, must be `conversation.item.input_audio_transcription.failed`. + */ + type: 'conversation.item.input_audio_transcription.failed'; +} + +export namespace ConversationItemInputAudioTranscriptionFailedEvent { + /** + * Details of the transcription error. + */ + export interface Error { + /** + * Error code, if any. + */ + code?: string; + + /** + * A human-readable error message. + */ + message?: string; + + /** + * Parameter related to the error, if any. + */ + param?: string; + + /** + * The type of error. + */ + type?: string; + } +} + +/** + * Send this event to truncate a previous assistant message’s audio. The server + * will produce audio faster than realtime, so this event is useful when the user + * interrupts to truncate audio that has already been sent to the client but not + * yet played. This will synchronize the server's understanding of the audio with + * the client's playback. + * + * Truncating audio will delete the server-side text transcript to ensure there is + * not text in the context that hasn't been heard by the user. + * + * If successful, the server will respond with a `conversation.item.truncated` + * event. + */ +export interface ConversationItemTruncateEvent { + /** + * Inclusive duration up to which audio is truncated, in milliseconds. If the + * audio_end_ms is greater than the actual audio duration, the server will respond + * with an error. + */ + audio_end_ms: number; + + /** + * The index of the content part to truncate. Set this to 0. + */ + content_index: number; + + /** + * The ID of the assistant message item to truncate. Only assistant message items + * can be truncated. + */ + item_id: string; + + /** + * The event type, must be `conversation.item.truncate`. + */ + type: 'conversation.item.truncate'; + + /** + * Optional client-generated ID used to identify this event. + */ + event_id?: string; +} + +/** + * Returned when an earlier assistant audio message item is truncated by the client + * with a `conversation.item.truncate` event. This event is used to synchronize the + * server's understanding of the audio with the client's playback. + * + * This action will truncate the audio and remove the server-side text transcript + * to ensure there is no text in the context that hasn't been heard by the user. + */ +export interface ConversationItemTruncatedEvent { + /** + * The duration up to which the audio was truncated, in milliseconds. + */ + audio_end_ms: number; + + /** + * The index of the content part that was truncated. + */ + content_index: number; + + /** + * The unique ID of the server event. + */ + event_id: string; + + /** + * The ID of the assistant message item that was truncated. + */ + item_id: string; + + /** + * The event type, must be `conversation.item.truncated`. + */ + type: 'conversation.item.truncated'; +} + +/** + * The item to add to the conversation. + */ +export interface ConversationItemWithReference { + /** + * For an item of type (`message` | `function_call` | `function_call_output`) this + * field allows the client to assign the unique ID of the item. It is not required + * because the server will generate one if not provided. + * + * For an item of type `item_reference`, this field is required and is a reference + * to any item that has previously existed in the conversation. + */ + id?: string; + + /** + * The arguments of the function call (for `function_call` items). + */ + arguments?: string; + + /** + * The ID of the function call (for `function_call` and `function_call_output` + * items). If passed on a `function_call_output` item, the server will check that a + * `function_call` item with the same ID exists in the conversation history. + */ + call_id?: string; + + /** + * The content of the message, applicable for `message` items. + * + * - Message items of role `system` support only `input_text` content + * - Message items of role `user` support `input_text` and `input_audio` content + * - Message items of role `assistant` support `text` content. + */ + content?: Array; + + /** + * The name of the function being called (for `function_call` items). + */ + name?: string; + + /** + * Identifier for the API object being returned - always `realtime.item`. + */ + object?: 'realtime.item'; + + /** + * The output of the function call (for `function_call_output` items). + */ + output?: string; + + /** + * The role of the message sender (`user`, `assistant`, `system`), only applicable + * for `message` items. + */ + role?: 'user' | 'assistant' | 'system'; + + /** + * The status of the item (`completed`, `incomplete`). These have no effect on the + * conversation, but are accepted for consistency with the + * `conversation.item.created` event. + */ + status?: 'completed' | 'incomplete'; + + /** + * The type of the item (`message`, `function_call`, `function_call_output`, + * `item_reference`). + */ + type?: 'message' | 'function_call' | 'function_call_output' | 'item_reference'; +} + +/** + * Returned when an error occurs, which could be a client problem or a server + * problem. Most errors are recoverable and the session will stay open, we + * recommend to implementors to monitor and log error messages by default. + */ +export interface ErrorEvent { + /** + * Details of the error. + */ + error: ErrorEvent.Error; + + /** + * The unique ID of the server event. + */ + event_id: string; + + /** + * The event type, must be `error`. + */ + type: 'error'; +} + +export namespace ErrorEvent { + /** + * Details of the error. + */ + export interface Error { + /** + * A human-readable error message. + */ + message: string; + + /** + * The type of error (e.g., "invalid_request_error", "server_error"). + */ + type: string; + + /** + * Error code, if any. + */ + code?: string | null; + + /** + * The event_id of the client event that caused the error, if applicable. + */ + event_id?: string | null; + + /** + * Parameter related to the error, if any. + */ + param?: string | null; + } +} + +/** + * Send this event to append audio bytes to the input audio buffer. The audio + * buffer is temporary storage you can write to and later commit. In Server VAD + * mode, the audio buffer is used to detect speech and the server will decide when + * to commit. When Server VAD is disabled, you must commit the audio buffer + * manually. + * + * The client may choose how much audio to place in each event up to a maximum of + * 15 MiB, for example streaming smaller chunks from the client may allow the VAD + * to be more responsive. Unlike made other client events, the server will not send + * a confirmation response to this event. + */ +export interface InputAudioBufferAppendEvent { + /** + * Base64-encoded audio bytes. This must be in the format specified by the + * `input_audio_format` field in the session configuration. + */ + audio: string; + + /** + * The event type, must be `input_audio_buffer.append`. + */ + type: 'input_audio_buffer.append'; + + /** + * Optional client-generated ID used to identify this event. + */ + event_id?: string; +} + +/** + * Send this event to clear the audio bytes in the buffer. The server will respond + * with an `input_audio_buffer.cleared` event. + */ +export interface InputAudioBufferClearEvent { + /** + * The event type, must be `input_audio_buffer.clear`. + */ + type: 'input_audio_buffer.clear'; + + /** + * Optional client-generated ID used to identify this event. + */ + event_id?: string; +} + +/** + * Returned when the input audio buffer is cleared by the client with a + * `input_audio_buffer.clear` event. + */ +export interface InputAudioBufferClearedEvent { + /** + * The unique ID of the server event. + */ + event_id: string; + + /** + * The event type, must be `input_audio_buffer.cleared`. + */ + type: 'input_audio_buffer.cleared'; +} + +/** + * Send this event to commit the user input audio buffer, which will create a new + * user message item in the conversation. This event will produce an error if the + * input audio buffer is empty. When in Server VAD mode, the client does not need + * to send this event, the server will commit the audio buffer automatically. + * + * Committing the input audio buffer will trigger input audio transcription (if + * enabled in session configuration), but it will not create a response from the + * model. The server will respond with an `input_audio_buffer.committed` event. + */ +export interface InputAudioBufferCommitEvent { + /** + * The event type, must be `input_audio_buffer.commit`. + */ + type: 'input_audio_buffer.commit'; + + /** + * Optional client-generated ID used to identify this event. + */ + event_id?: string; +} + +/** + * Returned when an input audio buffer is committed, either by the client or + * automatically in server VAD mode. The `item_id` property is the ID of the user + * message item that will be created, thus a `conversation.item.created` event will + * also be sent to the client. + */ +export interface InputAudioBufferCommittedEvent { + /** + * The unique ID of the server event. + */ + event_id: string; + + /** + * The ID of the user message item that will be created. + */ + item_id: string; + + /** + * The ID of the preceding item after which the new item will be inserted. + */ + previous_item_id: string; + + /** + * The event type, must be `input_audio_buffer.committed`. + */ + type: 'input_audio_buffer.committed'; +} + +/** + * Sent by the server when in `server_vad` mode to indicate that speech has been + * detected in the audio buffer. This can happen any time audio is added to the + * buffer (unless speech is already detected). The client may want to use this + * event to interrupt audio playback or provide visual feedback to the user. + * + * The client should expect to receive a `input_audio_buffer.speech_stopped` event + * when speech stops. The `item_id` property is the ID of the user message item + * that will be created when speech stops and will also be included in the + * `input_audio_buffer.speech_stopped` event (unless the client manually commits + * the audio buffer during VAD activation). + */ +export interface InputAudioBufferSpeechStartedEvent { + /** + * Milliseconds from the start of all audio written to the buffer during the + * session when speech was first detected. This will correspond to the beginning of + * audio sent to the model, and thus includes the `prefix_padding_ms` configured in + * the Session. + */ + audio_start_ms: number; + + /** + * The unique ID of the server event. + */ + event_id: string; + + /** + * The ID of the user message item that will be created when speech stops. + */ + item_id: string; + + /** + * The event type, must be `input_audio_buffer.speech_started`. + */ + type: 'input_audio_buffer.speech_started'; +} + +/** + * Returned in `server_vad` mode when the server detects the end of speech in the + * audio buffer. The server will also send an `conversation.item.created` event + * with the user message item that is created from the audio buffer. + */ +export interface InputAudioBufferSpeechStoppedEvent { + /** + * Milliseconds since the session started when speech stopped. This will correspond + * to the end of audio sent to the model, and thus includes the + * `min_silence_duration_ms` configured in the Session. + */ + audio_end_ms: number; + + /** + * The unique ID of the server event. + */ + event_id: string; + + /** + * The ID of the user message item that will be created. + */ + item_id: string; + + /** + * The event type, must be `input_audio_buffer.speech_stopped`. + */ + type: 'input_audio_buffer.speech_stopped'; +} + +/** + * Emitted at the beginning of a Response to indicate the updated rate limits. When + * a Response is created some tokens will be "reserved" for the output tokens, the + * rate limits shown here reflect that reservation, which is then adjusted + * accordingly once the Response is completed. + */ +export interface RateLimitsUpdatedEvent { + /** + * The unique ID of the server event. + */ + event_id: string; + + /** + * List of rate limit information. + */ + rate_limits: Array; + + /** + * The event type, must be `rate_limits.updated`. + */ + type: 'rate_limits.updated'; +} + +export namespace RateLimitsUpdatedEvent { + export interface RateLimit { + /** + * The maximum allowed value for the rate limit. + */ + limit?: number; + + /** + * The name of the rate limit (`requests`, `tokens`). + */ + name?: 'requests' | 'tokens'; + + /** + * The remaining value before the limit is reached. + */ + remaining?: number; + + /** + * Seconds until the rate limit resets. + */ + reset_seconds?: number; + } +} + +/** + * All events that the client can send to the Realtime API + */ +export type RealtimeClientEvent = + | SessionUpdateEvent + | InputAudioBufferAppendEvent + | InputAudioBufferCommitEvent + | InputAudioBufferClearEvent + | ConversationItemCreateEvent + | ConversationItemTruncateEvent + | ConversationItemDeleteEvent + | ResponseCreateEvent + | ResponseCancelEvent; + +/** + * The response resource. + */ +export interface RealtimeResponse { + /** + * The unique ID of the response. + */ + id?: string; + + /** + * Which conversation the response is added to, determined by the `conversation` + * field in the `response.create` event. If `auto`, the response will be added to + * the default conversation and the value of `conversation_id` will be an id like + * `conv_1234`. If `none`, the response will not be added to any conversation and + * the value of `conversation_id` will be `null`. If responses are being triggered + * by server VAD, the response will be added to the default conversation, thus the + * `conversation_id` will be an id like `conv_1234`. + */ + conversation_id?: string; + + /** + * Maximum number of output tokens for a single assistant response, inclusive of + * tool calls, that was used in this response. + */ + max_output_tokens?: number | 'inf'; + + /** + * Set of 16 key-value pairs that can be attached to an object. This can be useful + * for storing additional information about the object in a structured format, and + * querying for objects via API or the dashboard. + * + * Keys are strings with a maximum length of 64 characters. Values are strings with + * a maximum length of 512 characters. + */ + metadata?: Shared.Metadata | null; + + /** + * The set of modalities the model used to respond. If there are multiple + * modalities, the model will pick one, for example if `modalities` is + * `["text", "audio"]`, the model could be responding in either text or audio. + */ + modalities?: Array<'text' | 'audio'>; + + /** + * The object type, must be `realtime.response`. + */ + object?: 'realtime.response'; + + /** + * The list of output items generated by the response. + */ + output?: Array; + + /** + * The format of output audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. + */ + output_audio_format?: 'pcm16' | 'g711_ulaw' | 'g711_alaw'; + + /** + * The final status of the response (`completed`, `cancelled`, `failed`, or + * `incomplete`). + */ + status?: 'completed' | 'cancelled' | 'failed' | 'incomplete'; + + /** + * Additional details about the status. + */ + status_details?: RealtimeResponseStatus; + + /** + * Sampling temperature for the model, limited to [0.6, 1.2]. Defaults to 0.8. + */ + temperature?: number; + + /** + * Usage statistics for the Response, this will correspond to billing. A Realtime + * API session will maintain a conversation context and append new Items to the + * Conversation, thus output from previous turns (text and audio tokens) will + * become the input for later turns. + */ + usage?: RealtimeResponseUsage; + + /** + * The voice the model used to respond. Current voice options are `alloy`, `ash`, + * `ballad`, `coral`, `echo` `sage`, `shimmer` and `verse`. + */ + voice?: 'alloy' | 'ash' | 'ballad' | 'coral' | 'echo' | 'sage' | 'shimmer' | 'verse'; +} + +/** + * Additional details about the status. + */ +export interface RealtimeResponseStatus { + /** + * A description of the error that caused the response to fail, populated when the + * `status` is `failed`. + */ + error?: RealtimeResponseStatus.Error; + + /** + * The reason the Response did not complete. For a `cancelled` Response, one of + * `turn_detected` (the server VAD detected a new start of speech) or + * `client_cancelled` (the client sent a cancel event). For an `incomplete` + * Response, one of `max_output_tokens` or `content_filter` (the server-side safety + * filter activated and cut off the response). + */ + reason?: 'turn_detected' | 'client_cancelled' | 'max_output_tokens' | 'content_filter'; + + /** + * The type of error that caused the response to fail, corresponding with the + * `status` field (`completed`, `cancelled`, `incomplete`, `failed`). + */ + type?: 'completed' | 'cancelled' | 'incomplete' | 'failed'; +} + +export namespace RealtimeResponseStatus { + /** + * A description of the error that caused the response to fail, populated when the + * `status` is `failed`. + */ + export interface Error { + /** + * Error code, if any. + */ + code?: string; + + /** + * The type of error. + */ + type?: string; + } +} + +/** + * Usage statistics for the Response, this will correspond to billing. A Realtime + * API session will maintain a conversation context and append new Items to the + * Conversation, thus output from previous turns (text and audio tokens) will + * become the input for later turns. + */ +export interface RealtimeResponseUsage { + /** + * Details about the input tokens used in the Response. + */ + input_token_details?: RealtimeResponseUsage.InputTokenDetails; + + /** + * The number of input tokens used in the Response, including text and audio + * tokens. + */ + input_tokens?: number; + + /** + * Details about the output tokens used in the Response. + */ + output_token_details?: RealtimeResponseUsage.OutputTokenDetails; + + /** + * The number of output tokens sent in the Response, including text and audio + * tokens. + */ + output_tokens?: number; + + /** + * The total number of tokens in the Response including input and output text and + * audio tokens. + */ + total_tokens?: number; +} + +export namespace RealtimeResponseUsage { + /** + * Details about the input tokens used in the Response. + */ + export interface InputTokenDetails { + /** + * The number of audio tokens used in the Response. + */ + audio_tokens?: number; + + /** + * The number of cached tokens used in the Response. + */ + cached_tokens?: number; + + /** + * The number of text tokens used in the Response. + */ + text_tokens?: number; + } + + /** + * Details about the output tokens used in the Response. + */ + export interface OutputTokenDetails { + /** + * The number of audio tokens used in the Response. + */ + audio_tokens?: number; + + /** + * The number of text tokens used in the Response. + */ + text_tokens?: number; + } +} + +/** + * All events that the Realtime API can send back + */ +export type RealtimeServerEvent = + | ErrorEvent + | SessionCreatedEvent + | SessionUpdatedEvent + | ConversationCreatedEvent + | InputAudioBufferCommittedEvent + | InputAudioBufferClearedEvent + | InputAudioBufferSpeechStartedEvent + | InputAudioBufferSpeechStoppedEvent + | ConversationItemCreatedEvent + | ConversationItemInputAudioTranscriptionCompletedEvent + | ConversationItemInputAudioTranscriptionFailedEvent + | ConversationItemTruncatedEvent + | ConversationItemDeletedEvent + | ResponseCreatedEvent + | ResponseDoneEvent + | ResponseOutputItemAddedEvent + | ResponseOutputItemDoneEvent + | ResponseContentPartAddedEvent + | ResponseContentPartDoneEvent + | ResponseTextDeltaEvent + | ResponseTextDoneEvent + | ResponseAudioTranscriptDeltaEvent + | ResponseAudioTranscriptDoneEvent + | ResponseAudioDeltaEvent + | ResponseAudioDoneEvent + | ResponseFunctionCallArgumentsDeltaEvent + | ResponseFunctionCallArgumentsDoneEvent + | RateLimitsUpdatedEvent; + +/** + * Returned when the model-generated audio is updated. + */ +export interface ResponseAudioDeltaEvent { + /** + * The index of the content part in the item's content array. + */ + content_index: number; + + /** + * Base64-encoded audio data delta. + */ + delta: string; + + /** + * The unique ID of the server event. + */ + event_id: string; + + /** + * The ID of the item. + */ + item_id: string; + + /** + * The index of the output item in the response. + */ + output_index: number; + + /** + * The ID of the response. + */ + response_id: string; + + /** + * The event type, must be `response.audio.delta`. + */ + type: 'response.audio.delta'; +} + +/** + * Returned when the model-generated audio is done. Also emitted when a Response is + * interrupted, incomplete, or cancelled. + */ +export interface ResponseAudioDoneEvent { + /** + * The index of the content part in the item's content array. + */ + content_index: number; + + /** + * The unique ID of the server event. + */ + event_id: string; + + /** + * The ID of the item. + */ + item_id: string; + + /** + * The index of the output item in the response. + */ + output_index: number; + + /** + * The ID of the response. + */ + response_id: string; + + /** + * The event type, must be `response.audio.done`. + */ + type: 'response.audio.done'; +} + +/** + * Returned when the model-generated transcription of audio output is updated. + */ +export interface ResponseAudioTranscriptDeltaEvent { + /** + * The index of the content part in the item's content array. + */ + content_index: number; + + /** + * The transcript delta. + */ + delta: string; + + /** + * The unique ID of the server event. + */ + event_id: string; + + /** + * The ID of the item. + */ + item_id: string; + + /** + * The index of the output item in the response. + */ + output_index: number; + + /** + * The ID of the response. + */ + response_id: string; + + /** + * The event type, must be `response.audio_transcript.delta`. + */ + type: 'response.audio_transcript.delta'; +} + +/** + * Returned when the model-generated transcription of audio output is done + * streaming. Also emitted when a Response is interrupted, incomplete, or + * cancelled. + */ +export interface ResponseAudioTranscriptDoneEvent { + /** + * The index of the content part in the item's content array. + */ + content_index: number; + + /** + * The unique ID of the server event. + */ + event_id: string; + + /** + * The ID of the item. + */ + item_id: string; + + /** + * The index of the output item in the response. + */ + output_index: number; + + /** + * The ID of the response. + */ + response_id: string; + + /** + * The final transcript of the audio. + */ + transcript: string; + + /** + * The event type, must be `response.audio_transcript.done`. + */ + type: 'response.audio_transcript.done'; +} + +/** + * Send this event to cancel an in-progress response. The server will respond with + * a `response.cancelled` event or an error if there is no response to cancel. + */ +export interface ResponseCancelEvent { + /** + * The event type, must be `response.cancel`. + */ + type: 'response.cancel'; + + /** + * Optional client-generated ID used to identify this event. + */ + event_id?: string; + + /** + * A specific response ID to cancel - if not provided, will cancel an in-progress + * response in the default conversation. + */ + response_id?: string; +} + +/** + * Returned when a new content part is added to an assistant message item during + * response generation. + */ +export interface ResponseContentPartAddedEvent { + /** + * The index of the content part in the item's content array. + */ + content_index: number; + + /** + * The unique ID of the server event. + */ + event_id: string; + + /** + * The ID of the item to which the content part was added. + */ + item_id: string; + + /** + * The index of the output item in the response. + */ + output_index: number; + + /** + * The content part that was added. + */ + part: ResponseContentPartAddedEvent.Part; + + /** + * The ID of the response. + */ + response_id: string; + + /** + * The event type, must be `response.content_part.added`. + */ + type: 'response.content_part.added'; +} + +export namespace ResponseContentPartAddedEvent { + /** + * The content part that was added. + */ + export interface Part { + /** + * Base64-encoded audio data (if type is "audio"). + */ + audio?: string; + + /** + * The text content (if type is "text"). + */ + text?: string; + + /** + * The transcript of the audio (if type is "audio"). + */ + transcript?: string; + + /** + * The content type ("text", "audio"). + */ + type?: 'text' | 'audio'; + } +} + +/** + * Returned when a content part is done streaming in an assistant message item. + * Also emitted when a Response is interrupted, incomplete, or cancelled. + */ +export interface ResponseContentPartDoneEvent { + /** + * The index of the content part in the item's content array. + */ + content_index: number; + + /** + * The unique ID of the server event. + */ + event_id: string; + + /** + * The ID of the item. + */ + item_id: string; + + /** + * The index of the output item in the response. + */ + output_index: number; + + /** + * The content part that is done. + */ + part: ResponseContentPartDoneEvent.Part; + + /** + * The ID of the response. + */ + response_id: string; + + /** + * The event type, must be `response.content_part.done`. + */ + type: 'response.content_part.done'; +} + +export namespace ResponseContentPartDoneEvent { + /** + * The content part that is done. + */ + export interface Part { + /** + * Base64-encoded audio data (if type is "audio"). + */ + audio?: string; + + /** + * The text content (if type is "text"). + */ + text?: string; + + /** + * The transcript of the audio (if type is "audio"). + */ + transcript?: string; + + /** + * The content type ("text", "audio"). + */ + type?: 'text' | 'audio'; + } +} + +/** + * This event instructs the server to create a Response, which means triggering + * model inference. When in Server VAD mode, the server will create Responses + * automatically. + * + * A Response will include at least one Item, and may have two, in which case the + * second will be a function call. These Items will be appended to the conversation + * history. + * + * The server will respond with a `response.created` event, events for Items and + * content created, and finally a `response.done` event to indicate the Response is + * complete. + * + * The `response.create` event includes inference configuration like + * `instructions`, and `temperature`. These fields will override the Session's + * configuration for this Response only. + */ +export interface ResponseCreateEvent { + /** + * The event type, must be `response.create`. + */ + type: 'response.create'; + + /** + * Optional client-generated ID used to identify this event. + */ + event_id?: string; + + /** + * Create a new Realtime response with these parameters + */ + response?: ResponseCreateEvent.Response; +} + +export namespace ResponseCreateEvent { + /** + * Create a new Realtime response with these parameters + */ + export interface Response { + /** + * Controls which conversation the response is added to. Currently supports `auto` + * and `none`, with `auto` as the default value. The `auto` value means that the + * contents of the response will be added to the default conversation. Set this to + * `none` to create an out-of-band response which will not add items to default + * conversation. + */ + conversation?: (string & {}) | 'auto' | 'none'; + + /** + * Input items to include in the prompt for the model. Using this field creates a + * new context for this Response instead of using the default conversation. An + * empty array `[]` will clear the context for this Response. Note that this can + * include references to items from the default conversation. + */ + input?: Array; + + /** + * The default system instructions (i.e. system message) prepended to model calls. + * This field allows the client to guide the model on desired responses. The model + * can be instructed on response content and format, (e.g. "be extremely succinct", + * "act friendly", "here are examples of good responses") and on audio behavior + * (e.g. "talk quickly", "inject emotion into your voice", "laugh frequently"). The + * instructions are not guaranteed to be followed by the model, but they provide + * guidance to the model on the desired behavior. + * + * Note that the server sets default instructions which will be used if this field + * is not set and are visible in the `session.created` event at the start of the + * session. + */ + instructions?: string; + + /** + * Maximum number of output tokens for a single assistant response, inclusive of + * tool calls. Provide an integer between 1 and 4096 to limit output tokens, or + * `inf` for the maximum available tokens for a given model. Defaults to `inf`. + */ + max_response_output_tokens?: number | 'inf'; + + /** + * Set of 16 key-value pairs that can be attached to an object. This can be useful + * for storing additional information about the object in a structured format, and + * querying for objects via API or the dashboard. + * + * Keys are strings with a maximum length of 64 characters. Values are strings with + * a maximum length of 512 characters. + */ + metadata?: Shared.Metadata | null; + + /** + * The set of modalities the model can respond with. To disable audio, set this to + * ["text"]. + */ + modalities?: Array<'text' | 'audio'>; + + /** + * The format of output audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. + */ + output_audio_format?: 'pcm16' | 'g711_ulaw' | 'g711_alaw'; + + /** + * Sampling temperature for the model, limited to [0.6, 1.2]. Defaults to 0.8. + */ + temperature?: number; + + /** + * How the model chooses tools. Options are `auto`, `none`, `required`, or specify + * a function, like `{"type": "function", "function": {"name": "my_function"}}`. + */ + tool_choice?: string; + + /** + * Tools (functions) available to the model. + */ + tools?: Array; + + /** + * The voice the model uses to respond. Voice cannot be changed during the session + * once the model has responded with audio at least once. Current voice options are + * `alloy`, `ash`, `ballad`, `coral`, `echo` `sage`, `shimmer` and `verse`. + */ + voice?: 'alloy' | 'ash' | 'ballad' | 'coral' | 'echo' | 'sage' | 'shimmer' | 'verse'; + } + + export namespace Response { + export interface Tool { + /** + * The description of the function, including guidance on when and how to call it, + * and guidance about what to tell the user when calling (if anything). + */ + description?: string; + + /** + * The name of the function. + */ + name?: string; + + /** + * Parameters of the function in JSON Schema. + */ + parameters?: unknown; + + /** + * The type of the tool, i.e. `function`. + */ + type?: 'function'; + } + } +} + +/** + * Returned when a new Response is created. The first event of response creation, + * where the response is in an initial state of `in_progress`. + */ +export interface ResponseCreatedEvent { + /** + * The unique ID of the server event. + */ + event_id: string; + + /** + * The response resource. + */ + response: RealtimeResponse; + + /** + * The event type, must be `response.created`. + */ + type: 'response.created'; +} + +/** + * Returned when a Response is done streaming. Always emitted, no matter the final + * state. The Response object included in the `response.done` event will include + * all output Items in the Response but will omit the raw audio data. + */ +export interface ResponseDoneEvent { + /** + * The unique ID of the server event. + */ + event_id: string; + + /** + * The response resource. + */ + response: RealtimeResponse; + + /** + * The event type, must be `response.done`. + */ + type: 'response.done'; +} + +/** + * Returned when the model-generated function call arguments are updated. + */ +export interface ResponseFunctionCallArgumentsDeltaEvent { + /** + * The ID of the function call. + */ + call_id: string; + + /** + * The arguments delta as a JSON string. + */ + delta: string; + + /** + * The unique ID of the server event. + */ + event_id: string; + + /** + * The ID of the function call item. + */ + item_id: string; + + /** + * The index of the output item in the response. + */ + output_index: number; + + /** + * The ID of the response. + */ + response_id: string; + + /** + * The event type, must be `response.function_call_arguments.delta`. + */ + type: 'response.function_call_arguments.delta'; +} + +/** + * Returned when the model-generated function call arguments are done streaming. + * Also emitted when a Response is interrupted, incomplete, or cancelled. + */ +export interface ResponseFunctionCallArgumentsDoneEvent { + /** + * The final arguments as a JSON string. + */ + arguments: string; + + /** + * The ID of the function call. + */ + call_id: string; + + /** + * The unique ID of the server event. + */ + event_id: string; + + /** + * The ID of the function call item. + */ + item_id: string; + + /** + * The index of the output item in the response. + */ + output_index: number; + + /** + * The ID of the response. + */ + response_id: string; + + /** + * The event type, must be `response.function_call_arguments.done`. + */ + type: 'response.function_call_arguments.done'; +} + +/** + * Returned when a new Item is created during Response generation. + */ +export interface ResponseOutputItemAddedEvent { + /** + * The unique ID of the server event. + */ + event_id: string; + + /** + * The item to add to the conversation. + */ + item: ConversationItem; + + /** + * The index of the output item in the Response. + */ + output_index: number; + + /** + * The ID of the Response to which the item belongs. + */ + response_id: string; + + /** + * The event type, must be `response.output_item.added`. + */ + type: 'response.output_item.added'; +} + +/** + * Returned when an Item is done streaming. Also emitted when a Response is + * interrupted, incomplete, or cancelled. + */ +export interface ResponseOutputItemDoneEvent { + /** + * The unique ID of the server event. + */ + event_id: string; + + /** + * The item to add to the conversation. + */ + item: ConversationItem; + + /** + * The index of the output item in the Response. + */ + output_index: number; + + /** + * The ID of the Response to which the item belongs. + */ + response_id: string; + + /** + * The event type, must be `response.output_item.done`. + */ + type: 'response.output_item.done'; +} + +/** + * Returned when the text value of a "text" content part is updated. + */ +export interface ResponseTextDeltaEvent { + /** + * The index of the content part in the item's content array. + */ + content_index: number; + + /** + * The text delta. + */ + delta: string; + + /** + * The unique ID of the server event. + */ + event_id: string; + + /** + * The ID of the item. + */ + item_id: string; + + /** + * The index of the output item in the response. + */ + output_index: number; + + /** + * The ID of the response. + */ + response_id: string; + + /** + * The event type, must be `response.text.delta`. + */ + type: 'response.text.delta'; +} + +/** + * Returned when the text value of a "text" content part is done streaming. Also + * emitted when a Response is interrupted, incomplete, or cancelled. + */ +export interface ResponseTextDoneEvent { + /** + * The index of the content part in the item's content array. + */ + content_index: number; + + /** + * The unique ID of the server event. + */ + event_id: string; + + /** + * The ID of the item. + */ + item_id: string; + + /** + * The index of the output item in the response. + */ + output_index: number; + + /** + * The ID of the response. + */ + response_id: string; + + /** + * The final text content. + */ + text: string; + + /** + * The event type, must be `response.text.done`. + */ + type: 'response.text.done'; +} + +/** + * Returned when a Session is created. Emitted automatically when a new connection + * is established as the first server event. This event will contain the default + * Session configuration. + */ +export interface SessionCreatedEvent { + /** + * The unique ID of the server event. + */ + event_id: string; + + /** + * Realtime session object configuration. + */ + session: SessionsAPI.Session; + + /** + * The event type, must be `session.created`. + */ + type: 'session.created'; +} + +/** + * Send this event to update the session’s default configuration. The client may + * send this event at any time to update any field, except for `voice`. However, + * note that once a session has been initialized with a particular `model`, it + * can’t be changed to another model using `session.update`. + * + * When the server receives a `session.update`, it will respond with a + * `session.updated` event showing the full, effective configuration. Only the + * fields that are present are updated. To clear a field like `instructions`, pass + * an empty string. + */ +export interface SessionUpdateEvent { + /** + * Realtime session object configuration. + */ + session: SessionUpdateEvent.Session; + + /** + * The event type, must be `session.update`. + */ + type: 'session.update'; + + /** + * Optional client-generated ID used to identify this event. + */ + event_id?: string; +} + +export namespace SessionUpdateEvent { + /** + * Realtime session object configuration. + */ + export interface Session { + /** + * The format of input audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. For + * `pcm16`, input audio must be 16-bit PCM at a 24kHz sample rate, single channel + * (mono), and little-endian byte order. + */ + input_audio_format?: 'pcm16' | 'g711_ulaw' | 'g711_alaw'; + + /** + * Configuration for input audio transcription, defaults to off and can be set to + * `null` to turn off once on. Input audio transcription is not native to the + * model, since the model consumes audio directly. Transcription runs + * asynchronously through + * [OpenAI Whisper transcription](https://platform.openai.com/docs/api-reference/audio/createTranscription) + * and should be treated as rough guidance rather than the representation + * understood by the model. The client can optionally set the language and prompt + * for transcription, these fields will be passed to the Whisper API. + */ + input_audio_transcription?: Session.InputAudioTranscription; + + /** + * The default system instructions (i.e. system message) prepended to model calls. + * This field allows the client to guide the model on desired responses. The model + * can be instructed on response content and format, (e.g. "be extremely succinct", + * "act friendly", "here are examples of good responses") and on audio behavior + * (e.g. "talk quickly", "inject emotion into your voice", "laugh frequently"). The + * instructions are not guaranteed to be followed by the model, but they provide + * guidance to the model on the desired behavior. + * + * Note that the server sets default instructions which will be used if this field + * is not set and are visible in the `session.created` event at the start of the + * session. + */ + instructions?: string; + + /** + * Maximum number of output tokens for a single assistant response, inclusive of + * tool calls. Provide an integer between 1 and 4096 to limit output tokens, or + * `inf` for the maximum available tokens for a given model. Defaults to `inf`. + */ + max_response_output_tokens?: number | 'inf'; + + /** + * The set of modalities the model can respond with. To disable audio, set this to + * ["text"]. + */ + modalities?: Array<'text' | 'audio'>; + + /** + * The Realtime model used for this session. + */ + model?: + | 'gpt-4o-realtime-preview' + | 'gpt-4o-realtime-preview-2024-10-01' + | 'gpt-4o-realtime-preview-2024-12-17' + | 'gpt-4o-mini-realtime-preview' + | 'gpt-4o-mini-realtime-preview-2024-12-17'; + + /** + * The format of output audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. + * For `pcm16`, output audio is sampled at a rate of 24kHz. + */ + output_audio_format?: 'pcm16' | 'g711_ulaw' | 'g711_alaw'; + + /** + * Sampling temperature for the model, limited to [0.6, 1.2]. Defaults to 0.8. + */ + temperature?: number; + + /** + * How the model chooses tools. Options are `auto`, `none`, `required`, or specify + * a function. + */ + tool_choice?: string; + + /** + * Tools (functions) available to the model. + */ + tools?: Array; + + /** + * Configuration for turn detection. Can be set to `null` to turn off. Server VAD + * means that the model will detect the start and end of speech based on audio + * volume and respond at the end of user speech. + */ + turn_detection?: Session.TurnDetection; + + /** + * The voice the model uses to respond. Voice cannot be changed during the session + * once the model has responded with audio at least once. Current voice options are + * `alloy`, `ash`, `ballad`, `coral`, `echo` `sage`, `shimmer` and `verse`. + */ + voice?: 'alloy' | 'ash' | 'ballad' | 'coral' | 'echo' | 'sage' | 'shimmer' | 'verse'; + } + + export namespace Session { + /** + * Configuration for input audio transcription, defaults to off and can be set to + * `null` to turn off once on. Input audio transcription is not native to the + * model, since the model consumes audio directly. Transcription runs + * asynchronously through + * [OpenAI Whisper transcription](https://platform.openai.com/docs/api-reference/audio/createTranscription) + * and should be treated as rough guidance rather than the representation + * understood by the model. The client can optionally set the language and prompt + * for transcription, these fields will be passed to the Whisper API. + */ + export interface InputAudioTranscription { + /** + * The language of the input audio. Supplying the input language in + * [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) + * format will improve accuracy and latency. + */ + language?: string; + + /** + * The model to use for transcription, `whisper-1` is the only currently supported + * model. + */ + model?: string; + + /** + * An optional text to guide the model's style or continue a previous audio + * segment. The + * [prompt](https://platform.openai.com/docs/guides/speech-to-text#prompting) + * should match the audio language. + */ + prompt?: string; + } + + export interface Tool { + /** + * The description of the function, including guidance on when and how to call it, + * and guidance about what to tell the user when calling (if anything). + */ + description?: string; + + /** + * The name of the function. + */ + name?: string; + + /** + * Parameters of the function in JSON Schema. + */ + parameters?: unknown; + + /** + * The type of the tool, i.e. `function`. + */ + type?: 'function'; + } + + /** + * Configuration for turn detection. Can be set to `null` to turn off. Server VAD + * means that the model will detect the start and end of speech based on audio + * volume and respond at the end of user speech. + */ + export interface TurnDetection { + /** + * Whether or not to automatically generate a response when a VAD stop event + * occurs. `true` by default. + */ + create_response?: boolean; + + /** + * Whether or not to automatically interrupt any ongoing response with output to + * the default conversation (i.e. `conversation` of `auto`) when a VAD start event + * occurs. `true` by default. + */ + interrupt_response?: boolean; + + /** + * Amount of audio to include before the VAD detected speech (in milliseconds). + * Defaults to 300ms. + */ + prefix_padding_ms?: number; + + /** + * Duration of silence to detect speech stop (in milliseconds). Defaults to 500ms. + * With shorter values the model will respond more quickly, but may jump in on + * short pauses from the user. + */ + silence_duration_ms?: number; + + /** + * Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. A higher + * threshold will require louder audio to activate the model, and thus might + * perform better in noisy environments. + */ + threshold?: number; + + /** + * Type of turn detection, only `server_vad` is currently supported. + */ + type?: string; + } + } +} + +/** + * Returned when a session is updated with a `session.update` event, unless there + * is an error. + */ +export interface SessionUpdatedEvent { + /** + * The unique ID of the server event. + */ + event_id: string; + + /** + * Realtime session object configuration. + */ + session: SessionsAPI.Session; + + /** + * The event type, must be `session.updated`. + */ + type: 'session.updated'; +} + +Realtime.Sessions = Sessions; + +export declare namespace Realtime { + export { + Sessions as Sessions, + type SessionsAPISession as Session, + type SessionCreateResponse as SessionCreateResponse, + type SessionCreateParams as SessionCreateParams, + }; +} diff --git a/src/resources/beta/realtime/sessions.ts b/src/resources/beta/realtime/sessions.ts new file mode 100644 index 000000000..0ece95bcd --- /dev/null +++ b/src/resources/beta/realtime/sessions.ts @@ -0,0 +1,595 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../../../resource'; +import { APIPromise } from '../../../api-promise'; +import { buildHeaders } from '../../../internal/headers'; +import { RequestOptions } from '../../../internal/request-options'; + +export class Sessions extends APIResource { + /** + * Create an ephemeral API token for use in client-side applications with the + * Realtime API. Can be configured with the same session parameters as the + * `session.update` client event. + * + * It responds with a session object, plus a `client_secret` key which contains a + * usable ephemeral API token that can be used to authenticate browser clients for + * the Realtime API. + */ + create(body: SessionCreateParams, options?: RequestOptions): APIPromise { + return this._client.post('/realtime/sessions', { + body, + ...options, + headers: buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), + }); + } +} + +/** + * Realtime session object configuration. + */ +export interface Session { + /** + * Unique identifier for the session object. + */ + id?: string; + + /** + * The format of input audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. For + * `pcm16`, input audio must be 16-bit PCM at a 24kHz sample rate, single channel + * (mono), and little-endian byte order. + */ + input_audio_format?: 'pcm16' | 'g711_ulaw' | 'g711_alaw'; + + /** + * Configuration for input audio transcription, defaults to off and can be set to + * `null` to turn off once on. Input audio transcription is not native to the + * model, since the model consumes audio directly. Transcription runs + * asynchronously through Whisper and should be treated as rough guidance rather + * than the representation understood by the model. + */ + input_audio_transcription?: Session.InputAudioTranscription; + + /** + * The default system instructions (i.e. system message) prepended to model calls. + * This field allows the client to guide the model on desired responses. The model + * can be instructed on response content and format, (e.g. "be extremely succinct", + * "act friendly", "here are examples of good responses") and on audio behavior + * (e.g. "talk quickly", "inject emotion into your voice", "laugh frequently"). The + * instructions are not guaranteed to be followed by the model, but they provide + * guidance to the model on the desired behavior. + * + * Note that the server sets default instructions which will be used if this field + * is not set and are visible in the `session.created` event at the start of the + * session. + */ + instructions?: string; + + /** + * Maximum number of output tokens for a single assistant response, inclusive of + * tool calls. Provide an integer between 1 and 4096 to limit output tokens, or + * `inf` for the maximum available tokens for a given model. Defaults to `inf`. + */ + max_response_output_tokens?: number | 'inf'; + + /** + * The set of modalities the model can respond with. To disable audio, set this to + * ["text"]. + */ + modalities?: Array<'text' | 'audio'>; + + /** + * The Realtime model used for this session. + */ + model?: + | (string & {}) + | 'gpt-4o-realtime-preview' + | 'gpt-4o-realtime-preview-2024-10-01' + | 'gpt-4o-realtime-preview-2024-12-17' + | 'gpt-4o-mini-realtime-preview' + | 'gpt-4o-mini-realtime-preview-2024-12-17'; + + /** + * The format of output audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. + * For `pcm16`, output audio is sampled at a rate of 24kHz. + */ + output_audio_format?: 'pcm16' | 'g711_ulaw' | 'g711_alaw'; + + /** + * Sampling temperature for the model, limited to [0.6, 1.2]. Defaults to 0.8. + */ + temperature?: number; + + /** + * How the model chooses tools. Options are `auto`, `none`, `required`, or specify + * a function. + */ + tool_choice?: string; + + /** + * Tools (functions) available to the model. + */ + tools?: Array; + + /** + * Configuration for turn detection. Can be set to `null` to turn off. Server VAD + * means that the model will detect the start and end of speech based on audio + * volume and respond at the end of user speech. + */ + turn_detection?: Session.TurnDetection | null; + + /** + * The voice the model uses to respond. Voice cannot be changed during the session + * once the model has responded with audio at least once. Current voice options are + * `alloy`, `ash`, `ballad`, `coral`, `echo` `sage`, `shimmer` and `verse`. + */ + voice?: 'alloy' | 'ash' | 'ballad' | 'coral' | 'echo' | 'sage' | 'shimmer' | 'verse'; +} + +export namespace Session { + /** + * Configuration for input audio transcription, defaults to off and can be set to + * `null` to turn off once on. Input audio transcription is not native to the + * model, since the model consumes audio directly. Transcription runs + * asynchronously through Whisper and should be treated as rough guidance rather + * than the representation understood by the model. + */ + export interface InputAudioTranscription { + /** + * The model to use for transcription, `whisper-1` is the only currently supported + * model. + */ + model?: string; + } + + export interface Tool { + /** + * The description of the function, including guidance on when and how to call it, + * and guidance about what to tell the user when calling (if anything). + */ + description?: string; + + /** + * The name of the function. + */ + name?: string; + + /** + * Parameters of the function in JSON Schema. + */ + parameters?: unknown; + + /** + * The type of the tool, i.e. `function`. + */ + type?: 'function'; + } + + /** + * Configuration for turn detection. Can be set to `null` to turn off. Server VAD + * means that the model will detect the start and end of speech based on audio + * volume and respond at the end of user speech. + */ + export interface TurnDetection { + /** + * Whether or not to automatically generate a response when a VAD stop event + * occurs. `true` by default. + */ + create_response?: boolean; + + /** + * Whether or not to automatically interrupt any ongoing response with output to + * the default conversation (i.e. `conversation` of `auto`) when a VAD start event + * occurs. `true` by default. + */ + interrupt_response?: boolean; + + /** + * Amount of audio to include before the VAD detected speech (in milliseconds). + * Defaults to 300ms. + */ + prefix_padding_ms?: number; + + /** + * Duration of silence to detect speech stop (in milliseconds). Defaults to 500ms. + * With shorter values the model will respond more quickly, but may jump in on + * short pauses from the user. + */ + silence_duration_ms?: number; + + /** + * Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. A higher + * threshold will require louder audio to activate the model, and thus might + * perform better in noisy environments. + */ + threshold?: number; + + /** + * Type of turn detection, only `server_vad` is currently supported. + */ + type?: 'server_vad'; + } +} + +/** + * A new Realtime session configuration, with an ephermeral key. Default TTL for + * keys is one minute. + */ +export interface SessionCreateResponse { + /** + * Ephemeral key returned by the API. + */ + client_secret: SessionCreateResponse.ClientSecret; + + /** + * The format of input audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. + */ + input_audio_format?: string; + + /** + * Configuration for input audio transcription, defaults to off and can be set to + * `null` to turn off once on. Input audio transcription is not native to the + * model, since the model consumes audio directly. Transcription runs + * asynchronously through Whisper and should be treated as rough guidance rather + * than the representation understood by the model. + */ + input_audio_transcription?: SessionCreateResponse.InputAudioTranscription; + + /** + * The default system instructions (i.e. system message) prepended to model calls. + * This field allows the client to guide the model on desired responses. The model + * can be instructed on response content and format, (e.g. "be extremely succinct", + * "act friendly", "here are examples of good responses") and on audio behavior + * (e.g. "talk quickly", "inject emotion into your voice", "laugh frequently"). The + * instructions are not guaranteed to be followed by the model, but they provide + * guidance to the model on the desired behavior. + * + * Note that the server sets default instructions which will be used if this field + * is not set and are visible in the `session.created` event at the start of the + * session. + */ + instructions?: string; + + /** + * Maximum number of output tokens for a single assistant response, inclusive of + * tool calls. Provide an integer between 1 and 4096 to limit output tokens, or + * `inf` for the maximum available tokens for a given model. Defaults to `inf`. + */ + max_response_output_tokens?: number | 'inf'; + + /** + * The set of modalities the model can respond with. To disable audio, set this to + * ["text"]. + */ + modalities?: Array<'text' | 'audio'>; + + /** + * The format of output audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. + */ + output_audio_format?: string; + + /** + * Sampling temperature for the model, limited to [0.6, 1.2]. Defaults to 0.8. + */ + temperature?: number; + + /** + * How the model chooses tools. Options are `auto`, `none`, `required`, or specify + * a function. + */ + tool_choice?: string; + + /** + * Tools (functions) available to the model. + */ + tools?: Array; + + /** + * Configuration for turn detection. Can be set to `null` to turn off. Server VAD + * means that the model will detect the start and end of speech based on audio + * volume and respond at the end of user speech. + */ + turn_detection?: SessionCreateResponse.TurnDetection; + + /** + * The voice the model uses to respond. Voice cannot be changed during the session + * once the model has responded with audio at least once. Current voice options are + * `alloy`, `ash`, `ballad`, `coral`, `echo` `sage`, `shimmer` and `verse`. + */ + voice?: 'alloy' | 'ash' | 'ballad' | 'coral' | 'echo' | 'sage' | 'shimmer' | 'verse'; +} + +export namespace SessionCreateResponse { + /** + * Ephemeral key returned by the API. + */ + export interface ClientSecret { + /** + * Timestamp for when the token expires. Currently, all tokens expire after one + * minute. + */ + expires_at: number; + + /** + * Ephemeral key usable in client environments to authenticate connections to the + * Realtime API. Use this in client-side environments rather than a standard API + * token, which should only be used server-side. + */ + value: string; + } + + /** + * Configuration for input audio transcription, defaults to off and can be set to + * `null` to turn off once on. Input audio transcription is not native to the + * model, since the model consumes audio directly. Transcription runs + * asynchronously through Whisper and should be treated as rough guidance rather + * than the representation understood by the model. + */ + export interface InputAudioTranscription { + /** + * The model to use for transcription, `whisper-1` is the only currently supported + * model. + */ + model?: string; + } + + export interface Tool { + /** + * The description of the function, including guidance on when and how to call it, + * and guidance about what to tell the user when calling (if anything). + */ + description?: string; + + /** + * The name of the function. + */ + name?: string; + + /** + * Parameters of the function in JSON Schema. + */ + parameters?: unknown; + + /** + * The type of the tool, i.e. `function`. + */ + type?: 'function'; + } + + /** + * Configuration for turn detection. Can be set to `null` to turn off. Server VAD + * means that the model will detect the start and end of speech based on audio + * volume and respond at the end of user speech. + */ + export interface TurnDetection { + /** + * Amount of audio to include before the VAD detected speech (in milliseconds). + * Defaults to 300ms. + */ + prefix_padding_ms?: number; + + /** + * Duration of silence to detect speech stop (in milliseconds). Defaults to 500ms. + * With shorter values the model will respond more quickly, but may jump in on + * short pauses from the user. + */ + silence_duration_ms?: number; + + /** + * Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. A higher + * threshold will require louder audio to activate the model, and thus might + * perform better in noisy environments. + */ + threshold?: number; + + /** + * Type of turn detection, only `server_vad` is currently supported. + */ + type?: string; + } +} + +export interface SessionCreateParams { + /** + * The format of input audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. For + * `pcm16`, input audio must be 16-bit PCM at a 24kHz sample rate, single channel + * (mono), and little-endian byte order. + */ + input_audio_format?: 'pcm16' | 'g711_ulaw' | 'g711_alaw'; + + /** + * Configuration for input audio transcription, defaults to off and can be set to + * `null` to turn off once on. Input audio transcription is not native to the + * model, since the model consumes audio directly. Transcription runs + * asynchronously through + * [OpenAI Whisper transcription](https://platform.openai.com/docs/api-reference/audio/createTranscription) + * and should be treated as rough guidance rather than the representation + * understood by the model. The client can optionally set the language and prompt + * for transcription, these fields will be passed to the Whisper API. + */ + input_audio_transcription?: SessionCreateParams.InputAudioTranscription; + + /** + * The default system instructions (i.e. system message) prepended to model calls. + * This field allows the client to guide the model on desired responses. The model + * can be instructed on response content and format, (e.g. "be extremely succinct", + * "act friendly", "here are examples of good responses") and on audio behavior + * (e.g. "talk quickly", "inject emotion into your voice", "laugh frequently"). The + * instructions are not guaranteed to be followed by the model, but they provide + * guidance to the model on the desired behavior. + * + * Note that the server sets default instructions which will be used if this field + * is not set and are visible in the `session.created` event at the start of the + * session. + */ + instructions?: string; + + /** + * Maximum number of output tokens for a single assistant response, inclusive of + * tool calls. Provide an integer between 1 and 4096 to limit output tokens, or + * `inf` for the maximum available tokens for a given model. Defaults to `inf`. + */ + max_response_output_tokens?: number | 'inf'; + + /** + * The set of modalities the model can respond with. To disable audio, set this to + * ["text"]. + */ + modalities?: Array<'text' | 'audio'>; + + /** + * The Realtime model used for this session. + */ + model?: + | 'gpt-4o-realtime-preview' + | 'gpt-4o-realtime-preview-2024-10-01' + | 'gpt-4o-realtime-preview-2024-12-17' + | 'gpt-4o-mini-realtime-preview' + | 'gpt-4o-mini-realtime-preview-2024-12-17'; + + /** + * The format of output audio. Options are `pcm16`, `g711_ulaw`, or `g711_alaw`. + * For `pcm16`, output audio is sampled at a rate of 24kHz. + */ + output_audio_format?: 'pcm16' | 'g711_ulaw' | 'g711_alaw'; + + /** + * Sampling temperature for the model, limited to [0.6, 1.2]. Defaults to 0.8. + */ + temperature?: number; + + /** + * How the model chooses tools. Options are `auto`, `none`, `required`, or specify + * a function. + */ + tool_choice?: string; + + /** + * Tools (functions) available to the model. + */ + tools?: Array; + + /** + * Configuration for turn detection. Can be set to `null` to turn off. Server VAD + * means that the model will detect the start and end of speech based on audio + * volume and respond at the end of user speech. + */ + turn_detection?: SessionCreateParams.TurnDetection; + + /** + * The voice the model uses to respond. Voice cannot be changed during the session + * once the model has responded with audio at least once. Current voice options are + * `alloy`, `ash`, `ballad`, `coral`, `echo` `sage`, `shimmer` and `verse`. + */ + voice?: 'alloy' | 'ash' | 'ballad' | 'coral' | 'echo' | 'sage' | 'shimmer' | 'verse'; +} + +export namespace SessionCreateParams { + /** + * Configuration for input audio transcription, defaults to off and can be set to + * `null` to turn off once on. Input audio transcription is not native to the + * model, since the model consumes audio directly. Transcription runs + * asynchronously through + * [OpenAI Whisper transcription](https://platform.openai.com/docs/api-reference/audio/createTranscription) + * and should be treated as rough guidance rather than the representation + * understood by the model. The client can optionally set the language and prompt + * for transcription, these fields will be passed to the Whisper API. + */ + export interface InputAudioTranscription { + /** + * The language of the input audio. Supplying the input language in + * [ISO-639-1](https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) (e.g. `en`) + * format will improve accuracy and latency. + */ + language?: string; + + /** + * The model to use for transcription, `whisper-1` is the only currently supported + * model. + */ + model?: string; + + /** + * An optional text to guide the model's style or continue a previous audio + * segment. The + * [prompt](https://platform.openai.com/docs/guides/speech-to-text#prompting) + * should match the audio language. + */ + prompt?: string; + } + + export interface Tool { + /** + * The description of the function, including guidance on when and how to call it, + * and guidance about what to tell the user when calling (if anything). + */ + description?: string; + + /** + * The name of the function. + */ + name?: string; + + /** + * Parameters of the function in JSON Schema. + */ + parameters?: unknown; + + /** + * The type of the tool, i.e. `function`. + */ + type?: 'function'; + } + + /** + * Configuration for turn detection. Can be set to `null` to turn off. Server VAD + * means that the model will detect the start and end of speech based on audio + * volume and respond at the end of user speech. + */ + export interface TurnDetection { + /** + * Whether or not to automatically generate a response when a VAD stop event + * occurs. `true` by default. + */ + create_response?: boolean; + + /** + * Whether or not to automatically interrupt any ongoing response with output to + * the default conversation (i.e. `conversation` of `auto`) when a VAD start event + * occurs. `true` by default. + */ + interrupt_response?: boolean; + + /** + * Amount of audio to include before the VAD detected speech (in milliseconds). + * Defaults to 300ms. + */ + prefix_padding_ms?: number; + + /** + * Duration of silence to detect speech stop (in milliseconds). Defaults to 500ms. + * With shorter values the model will respond more quickly, but may jump in on + * short pauses from the user. + */ + silence_duration_ms?: number; + + /** + * Activation threshold for VAD (0.0 to 1.0), this defaults to 0.5. A higher + * threshold will require louder audio to activate the model, and thus might + * perform better in noisy environments. + */ + threshold?: number; + + /** + * Type of turn detection, only `server_vad` is currently supported. + */ + type?: string; + } +} + +export declare namespace Sessions { + export { + type Session as Session, + type SessionCreateResponse as SessionCreateResponse, + type SessionCreateParams as SessionCreateParams, + }; +} diff --git a/src/resources/beta/threads/index.ts b/src/resources/beta/threads/index.ts index f67a1edde..7eefa6553 100644 --- a/src/resources/beta/threads/index.ts +++ b/src/resources/beta/threads/index.ts @@ -1,7 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. export { - MessagesPage, Messages, type Annotation, type AnnotationDelta, @@ -32,11 +31,13 @@ export { type TextDelta, type TextDeltaBlock, type MessageCreateParams, + type MessageRetrieveParams, type MessageUpdateParams, type MessageListParams, + type MessageDeleteParams, + type MessagesPage, } from './messages'; export { - RunsPage, Runs, type RequiredActionFunctionToolCall, type Run, @@ -44,11 +45,14 @@ export { type RunCreateParams, type RunCreateParamsNonStreaming, type RunCreateParamsStreaming, + type RunRetrieveParams, type RunUpdateParams, type RunListParams, + type RunCancelParams, type RunSubmitToolOutputsParams, type RunSubmitToolOutputsParamsNonStreaming, type RunSubmitToolOutputsParamsStreaming, + type RunsPage, type RunCreateAndPollParams, type RunCreateAndStreamParams, type RunStreamParams, diff --git a/src/resources/beta/threads/messages.ts b/src/resources/beta/threads/messages.ts index 8124f56cd..3bba148b9 100644 --- a/src/resources/beta/threads/messages.ts +++ b/src/resources/beta/threads/messages.ts @@ -1,50 +1,46 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import { APIResource } from '../../../resource'; -import { isRequestOptions } from '../../../core'; -import * as Core from '../../../core'; +import * as Shared from '../../shared'; import * as AssistantsAPI from '../assistants'; -import { CursorPage, type CursorPageParams } from '../../../pagination'; +import { APIPromise } from '../../../api-promise'; +import { CursorPage, type CursorPageParams, PagePromise } from '../../../pagination'; +import { buildHeaders } from '../../../internal/headers'; +import { RequestOptions } from '../../../internal/request-options'; +import { path } from '../../../internal/utils/path'; export class Messages extends APIResource { /** * Create a message. */ - create( - threadId: string, - body: MessageCreateParams, - options?: Core.RequestOptions, - ): Core.APIPromise { - return this._client.post(`/threads/${threadId}/messages`, { + create(threadID: string, body: MessageCreateParams, options?: RequestOptions): APIPromise { + return this._client.post(path`/threads/${threadID}/messages`, { body, ...options, - headers: { 'OpenAI-Beta': 'assistants=v2', ...options?.headers }, + headers: buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), }); } /** * Retrieve a message. */ - retrieve(threadId: string, messageId: string, options?: Core.RequestOptions): Core.APIPromise { - return this._client.get(`/threads/${threadId}/messages/${messageId}`, { + retrieve(messageID: string, params: MessageRetrieveParams, options?: RequestOptions): APIPromise { + const { thread_id } = params; + return this._client.get(path`/threads/${thread_id}/messages/${messageID}`, { ...options, - headers: { 'OpenAI-Beta': 'assistants=v2', ...options?.headers }, + headers: buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), }); } /** * Modifies a message. */ - update( - threadId: string, - messageId: string, - body: MessageUpdateParams, - options?: Core.RequestOptions, - ): Core.APIPromise { - return this._client.post(`/threads/${threadId}/messages/${messageId}`, { + update(messageID: string, params: MessageUpdateParams, options?: RequestOptions): APIPromise { + const { thread_id, ...body } = params; + return this._client.post(path`/threads/${thread_id}/messages/${messageID}`, { body, ...options, - headers: { 'OpenAI-Beta': 'assistants=v2', ...options?.headers }, + headers: buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), }); } @@ -52,38 +48,34 @@ export class Messages extends APIResource { * Returns a list of messages for a given thread. */ list( - threadId: string, - query?: MessageListParams, - options?: Core.RequestOptions, - ): Core.PagePromise; - list(threadId: string, options?: Core.RequestOptions): Core.PagePromise; - list( - threadId: string, - query: MessageListParams | Core.RequestOptions = {}, - options?: Core.RequestOptions, - ): Core.PagePromise { - if (isRequestOptions(query)) { - return this.list(threadId, {}, query); - } - return this._client.getAPIList(`/threads/${threadId}/messages`, MessagesPage, { + threadID: string, + query: MessageListParams | null | undefined = {}, + options?: RequestOptions, + ): PagePromise { + return this._client.getAPIList(path`/threads/${threadID}/messages`, CursorPage, { query, ...options, - headers: { 'OpenAI-Beta': 'assistants=v2', ...options?.headers }, + headers: buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), }); } /** * Deletes a message. */ - del(threadId: string, messageId: string, options?: Core.RequestOptions): Core.APIPromise { - return this._client.delete(`/threads/${threadId}/messages/${messageId}`, { + delete( + messageID: string, + params: MessageDeleteParams, + options?: RequestOptions, + ): APIPromise { + const { thread_id } = params; + return this._client.delete(path`/threads/${thread_id}/messages/${messageID}`, { ...options, - headers: { 'OpenAI-Beta': 'assistants=v2', ...options?.headers }, + headers: buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), }); } } -export class MessagesPage extends CursorPage {} +export type MessagesPage = CursorPage; /** * A citation within the message that points to a specific quote from a specific @@ -407,11 +399,13 @@ export interface Message { /** * Set of 16 key-value pairs that can be attached to an object. This can be useful - * for storing additional information about the object in a structured format. Keys - * can be a maximum of 64 characters long and values can be a maxium of 512 - * characters long. + * for storing additional information about the object in a structured format, and + * querying for objects via API or the dashboard. + * + * Keys are strings with a maximum length of 64 characters. Values are strings with + * a maximum length of 512 characters. */ - metadata: unknown | null; + metadata: Shared.Metadata | null; /** * The object type, which is always `thread.message`. @@ -660,11 +654,13 @@ export interface MessageCreateParams { /** * Set of 16 key-value pairs that can be attached to an object. This can be useful - * for storing additional information about the object in a structured format. Keys - * can be a maximum of 64 characters long and values can be a maxium of 512 - * characters long. + * for storing additional information about the object in a structured format, and + * querying for objects via API or the dashboard. + * + * Keys are strings with a maximum length of 64 characters. Values are strings with + * a maximum length of 512 characters. */ - metadata?: unknown | null; + metadata?: Shared.Metadata | null; } export namespace MessageCreateParams { @@ -690,14 +686,29 @@ export namespace MessageCreateParams { } } +export interface MessageRetrieveParams { + /** + * The ID of the [thread](https://platform.openai.com/docs/api-reference/threads) + * to which this message belongs. + */ + thread_id: string; +} + export interface MessageUpdateParams { /** - * Set of 16 key-value pairs that can be attached to an object. This can be useful - * for storing additional information about the object in a structured format. Keys - * can be a maximum of 64 characters long and values can be a maxium of 512 - * characters long. + * Path param: The ID of the thread to which this message belongs. */ - metadata?: unknown | null; + thread_id: string; + + /** + * Body param: Set of 16 key-value pairs that can be attached to an object. This + * can be useful for storing additional information about the object in a + * structured format, and querying for objects via API or the dashboard. + * + * Keys are strings with a maximum length of 64 characters. Values are strings with + * a maximum length of 512 characters. + */ + metadata?: Shared.Metadata | null; } export interface MessageListParams extends CursorPageParams { @@ -721,7 +732,12 @@ export interface MessageListParams extends CursorPageParams { run_id?: string; } -Messages.MessagesPage = MessagesPage; +export interface MessageDeleteParams { + /** + * The ID of the thread to which this message belongs. + */ + thread_id: string; +} export declare namespace Messages { export { @@ -753,9 +769,11 @@ export declare namespace Messages { type TextContentBlockParam as TextContentBlockParam, type TextDelta as TextDelta, type TextDeltaBlock as TextDeltaBlock, - MessagesPage as MessagesPage, + type MessagesPage as MessagesPage, type MessageCreateParams as MessageCreateParams, + type MessageRetrieveParams as MessageRetrieveParams, type MessageUpdateParams as MessageUpdateParams, type MessageListParams as MessageListParams, + type MessageDeleteParams as MessageDeleteParams, }; } diff --git a/src/resources/beta/threads/runs/index.ts b/src/resources/beta/threads/runs/index.ts index 9dbe575bc..59c6a186c 100644 --- a/src/resources/beta/threads/runs/index.ts +++ b/src/resources/beta/threads/runs/index.ts @@ -1,7 +1,28 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. export { - RunStepsPage, + Runs, + type RequiredActionFunctionToolCall, + type Run, + type RunStatus, + type RunCreateParams, + type RunCreateParamsNonStreaming, + type RunCreateParamsStreaming, + type RunRetrieveParams, + type RunUpdateParams, + type RunListParams, + type RunCancelParams, + type RunSubmitToolOutputsParams, + type RunSubmitToolOutputsParamsNonStreaming, + type RunSubmitToolOutputsParamsStreaming, + type RunsPage, + type RunCreateAndPollParams, + type RunCreateAndStreamParams, + type RunStreamParams, + type RunSubmitToolOutputsAndPollParams, + type RunSubmitToolOutputsStreamParams, +} from './runs'; +export { Steps, type CodeInterpreterLogs, type CodeInterpreterOutputImage, @@ -13,34 +34,15 @@ export { type FunctionToolCallDelta, type MessageCreationStepDetails, type RunStep, + type RunStepInclude, type RunStepDelta, type RunStepDeltaEvent, type RunStepDeltaMessageDelta, - type RunStepInclude, type ToolCall, type ToolCallDelta, type ToolCallDeltaObject, type ToolCallsStepDetails, type StepRetrieveParams, type StepListParams, + type RunStepsPage, } from './steps'; -export { - RunsPage, - Runs, - type RequiredActionFunctionToolCall, - type Run, - type RunStatus, - type RunCreateParams, - type RunCreateParamsNonStreaming, - type RunCreateParamsStreaming, - type RunUpdateParams, - type RunListParams, - type RunCreateAndPollParams, - type RunCreateAndStreamParams, - type RunStreamParams, - type RunSubmitToolOutputsParams, - type RunSubmitToolOutputsParamsNonStreaming, - type RunSubmitToolOutputsParamsStreaming, - type RunSubmitToolOutputsAndPollParams, - type RunSubmitToolOutputsStreamParams, -} from './runs'; diff --git a/src/resources/beta/threads/runs/runs.ts b/src/resources/beta/threads/runs/runs.ts index 814ad3e89..1aafffc92 100644 --- a/src/resources/beta/threads/runs/runs.ts +++ b/src/resources/beta/threads/runs/runs.ts @@ -1,13 +1,8 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import { APIResource } from '../../../../resource'; -import { isRequestOptions } from '../../../../core'; -import { APIPromise } from '../../../../core'; -import * as Core from '../../../../core'; -import { AssistantStream, RunCreateParamsBaseStream } from '../../../../lib/AssistantStream'; -import { sleep } from '../../../../core'; -import { RunSubmitToolOutputsParamsStream } from '../../../../lib/AssistantStream'; import * as RunsAPI from './runs'; +import * as Shared from '../../../shared'; import * as AssistantsAPI from '../../assistants'; import * as ChatAPI from '../../../chat/chat'; import * as MessagesAPI from '../messages'; @@ -37,8 +32,15 @@ import { ToolCallDeltaObject, ToolCallsStepDetails, } from './steps'; -import { CursorPage, type CursorPageParams } from '../../../../pagination'; +import { APIPromise } from '../../../../api-promise'; +import { CursorPage, type CursorPageParams, PagePromise } from '../../../../pagination'; import { Stream } from '../../../../streaming'; +import { buildHeaders } from '../../../../internal/headers'; +import { RequestOptions } from '../../../../internal/request-options'; +import { AssistantStream, RunCreateParamsBaseStream } from '../../../../lib/AssistantStream'; +import { sleep } from '../../../../internal/utils/sleep'; +import { RunSubmitToolOutputsParamsStream } from '../../../../lib/AssistantStream'; +import { path } from '../../../../internal/utils/path'; export class Runs extends APIResource { steps: StepsAPI.Steps = new StepsAPI.Steps(this._client); @@ -46,32 +48,28 @@ export class Runs extends APIResource { /** * Create a run. */ + create(threadID: string, params: RunCreateParamsNonStreaming, options?: RequestOptions): APIPromise; create( - threadId: string, - params: RunCreateParamsNonStreaming, - options?: Core.RequestOptions, - ): APIPromise; - create( - threadId: string, + threadID: string, params: RunCreateParamsStreaming, - options?: Core.RequestOptions, + options?: RequestOptions, ): APIPromise>; create( - threadId: string, + threadID: string, params: RunCreateParamsBase, - options?: Core.RequestOptions, + options?: RequestOptions, ): APIPromise | Run>; create( - threadId: string, + threadID: string, params: RunCreateParams, - options?: Core.RequestOptions, + options?: RequestOptions, ): APIPromise | APIPromise> { const { include, ...body } = params; - return this._client.post(`/threads/${threadId}/runs`, { + return this._client.post(path`/threads/${threadID}/runs`, { query: { include }, body, ...options, - headers: { 'OpenAI-Beta': 'assistants=v2', ...options?.headers }, + headers: buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), stream: params.stream ?? false, }) as APIPromise | APIPromise>; } @@ -79,26 +77,23 @@ export class Runs extends APIResource { /** * Retrieves a run. */ - retrieve(threadId: string, runId: string, options?: Core.RequestOptions): Core.APIPromise { - return this._client.get(`/threads/${threadId}/runs/${runId}`, { + retrieve(runID: string, params: RunRetrieveParams, options?: RequestOptions): APIPromise { + const { thread_id } = params; + return this._client.get(path`/threads/${thread_id}/runs/${runID}`, { ...options, - headers: { 'OpenAI-Beta': 'assistants=v2', ...options?.headers }, + headers: buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), }); } /** * Modifies a run. */ - update( - threadId: string, - runId: string, - body: RunUpdateParams, - options?: Core.RequestOptions, - ): Core.APIPromise { - return this._client.post(`/threads/${threadId}/runs/${runId}`, { + update(runID: string, params: RunUpdateParams, options?: RequestOptions): APIPromise { + const { thread_id, ...body } = params; + return this._client.post(path`/threads/${thread_id}/runs/${runID}`, { body, ...options, - headers: { 'OpenAI-Beta': 'assistants=v2', ...options?.headers }, + headers: buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), }); } @@ -106,33 +101,25 @@ export class Runs extends APIResource { * Returns a list of runs belonging to a thread. */ list( - threadId: string, - query?: RunListParams, - options?: Core.RequestOptions, - ): Core.PagePromise; - list(threadId: string, options?: Core.RequestOptions): Core.PagePromise; - list( - threadId: string, - query: RunListParams | Core.RequestOptions = {}, - options?: Core.RequestOptions, - ): Core.PagePromise { - if (isRequestOptions(query)) { - return this.list(threadId, {}, query); - } - return this._client.getAPIList(`/threads/${threadId}/runs`, RunsPage, { + threadID: string, + query: RunListParams | null | undefined = {}, + options?: RequestOptions, + ): PagePromise { + return this._client.getAPIList(path`/threads/${threadID}/runs`, CursorPage, { query, ...options, - headers: { 'OpenAI-Beta': 'assistants=v2', ...options?.headers }, + headers: buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), }); } /** * Cancels a run that is `in_progress`. */ - cancel(threadId: string, runId: string, options?: Core.RequestOptions): Core.APIPromise { - return this._client.post(`/threads/${threadId}/runs/${runId}/cancel`, { + cancel(runID: string, params: RunCancelParams, options?: RequestOptions): APIPromise { + const { thread_id } = params; + return this._client.post(path`/threads/${thread_id}/runs/${runID}/cancel`, { ...options, - headers: { 'OpenAI-Beta': 'assistants=v2', ...options?.headers }, + headers: buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), }); } @@ -144,10 +131,10 @@ export class Runs extends APIResource { async createAndPoll( threadId: string, body: RunCreateParamsNonStreaming, - options?: Core.RequestOptions & { pollIntervalMs?: number }, + options?: RequestOptions & { pollIntervalMs?: number }, ): Promise { const run = await this.create(threadId, body, options); - return await this.poll(threadId, run.id, options); + return await this.poll(run.id, { thread_id: threadId }, options); } /** @@ -158,7 +145,7 @@ export class Runs extends APIResource { createAndStream( threadId: string, body: RunCreateParamsBaseStream, - options?: Core.RequestOptions, + options?: RequestOptions, ): AssistantStream { return AssistantStream.createAssistantStream(threadId, this._client.beta.threads.runs, body, options); } @@ -169,18 +156,20 @@ export class Runs extends APIResource { * https://platform.openai.com/docs/assistants/how-it-works/runs-and-run-steps */ async poll( - threadId: string, runId: string, - options?: Core.RequestOptions & { pollIntervalMs?: number }, + params: RunRetrieveParams, + options?: RequestOptions & { pollIntervalMs?: number }, ): Promise { - const headers: { [key: string]: string } = { ...options?.headers, 'X-Stainless-Poll-Helper': 'true' }; - - if (options?.pollIntervalMs) { - headers['X-Stainless-Custom-Poll-Interval'] = options.pollIntervalMs.toString(); - } + const headers = buildHeaders([ + options?.headers, + { + 'X-Stainless-Poll-Helper': 'true', + 'X-Stainless-Custom-Poll-Interval': options?.pollIntervalMs?.toString() ?? undefined, + }, + ]); while (true) { - const { data: run, response } = await this.retrieve(threadId, runId, { + const { data: run, response } = await this.retrieve(runId, params, { ...options, headers: { ...options?.headers, ...headers }, }).withResponse(); @@ -220,7 +209,7 @@ export class Runs extends APIResource { /** * Create a Run stream */ - stream(threadId: string, body: RunCreateParamsBaseStream, options?: Core.RequestOptions): AssistantStream { + stream(threadId: string, body: RunCreateParamsBaseStream, options?: RequestOptions): AssistantStream { return AssistantStream.createAssistantStream(threadId, this._client.beta.threads.runs, body, options); } @@ -231,34 +220,31 @@ export class Runs extends APIResource { * request. */ submitToolOutputs( - threadId: string, - runId: string, - body: RunSubmitToolOutputsParamsNonStreaming, - options?: Core.RequestOptions, + runID: string, + params: RunSubmitToolOutputsParamsNonStreaming, + options?: RequestOptions, ): APIPromise; submitToolOutputs( - threadId: string, - runId: string, - body: RunSubmitToolOutputsParamsStreaming, - options?: Core.RequestOptions, + runID: string, + params: RunSubmitToolOutputsParamsStreaming, + options?: RequestOptions, ): APIPromise>; submitToolOutputs( - threadId: string, - runId: string, - body: RunSubmitToolOutputsParamsBase, - options?: Core.RequestOptions, + runID: string, + params: RunSubmitToolOutputsParamsBase, + options?: RequestOptions, ): APIPromise | Run>; submitToolOutputs( - threadId: string, - runId: string, - body: RunSubmitToolOutputsParams, - options?: Core.RequestOptions, + runID: string, + params: RunSubmitToolOutputsParams, + options?: RequestOptions, ): APIPromise | APIPromise> { - return this._client.post(`/threads/${threadId}/runs/${runId}/submit_tool_outputs`, { + const { thread_id, ...body } = params; + return this._client.post(path`/threads/${thread_id}/runs/${runID}/submit_tool_outputs`, { body, ...options, - headers: { 'OpenAI-Beta': 'assistants=v2', ...options?.headers }, - stream: body.stream ?? false, + headers: buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), + stream: params.stream ?? false, }) as APIPromise | APIPromise>; } @@ -268,13 +254,12 @@ export class Runs extends APIResource { * https://platform.openai.com/docs/assistants/how-it-works/runs-and-run-steps */ async submitToolOutputsAndPoll( - threadId: string, runId: string, - body: RunSubmitToolOutputsParamsNonStreaming, - options?: Core.RequestOptions & { pollIntervalMs?: number }, + params: RunSubmitToolOutputsParamsNonStreaming, + options?: RequestOptions & { pollIntervalMs?: number }, ): Promise { - const run = await this.submitToolOutputs(threadId, runId, body, options); - return await this.poll(threadId, run.id, options); + const run = await this.submitToolOutputs(runId, params, options); + return await this.poll(run.id, params, options); } /** @@ -283,22 +268,15 @@ export class Runs extends APIResource { * https://platform.openai.com/docs/assistants/how-it-works/runs-and-run-steps */ submitToolOutputsStream( - threadId: string, runId: string, - body: RunSubmitToolOutputsParamsStream, - options?: Core.RequestOptions, + params: RunSubmitToolOutputsParamsStream, + options?: RequestOptions, ): AssistantStream { - return AssistantStream.createToolAssistantStream( - threadId, - runId, - this._client.beta.threads.runs, - body, - options, - ); + return AssistantStream.createToolAssistantStream(runId, this._client.beta.threads.runs, params, options); } } -export class RunsPage extends CursorPage {} +export type RunsPage = CursorPage; /** * Tool call objects @@ -415,11 +393,13 @@ export interface Run { /** * Set of 16 key-value pairs that can be attached to an object. This can be useful - * for storing additional information about the object in a structured format. Keys - * can be a maximum of 64 characters long and values can be a maxium of 512 - * characters long. + * for storing additional information about the object in a structured format, and + * querying for objects via API or the dashboard. + * + * Keys are strings with a maximum length of 64 characters. Values are strings with + * a maximum length of 512 characters. */ - metadata: unknown | null; + metadata: Shared.Metadata | null; /** * The model that the @@ -705,10 +685,12 @@ export interface RunCreateParamsBase { /** * Body param: Set of 16 key-value pairs that can be attached to an object. This * can be useful for storing additional information about the object in a - * structured format. Keys can be a maximum of 64 characters long and values can be - * a maxium of 512 characters long. + * structured format, and querying for objects via API or the dashboard. + * + * Keys are strings with a maximum length of 64 characters. Values are strings with + * a maximum length of 512 characters. */ - metadata?: unknown | null; + metadata?: Shared.Metadata | null; /** * Body param: The ID of the @@ -726,6 +708,16 @@ export interface RunCreateParamsBase { */ parallel_tool_calls?: boolean; + /** + * Body param: **o1 and o3-mini models only** + * + * Constrains effort on reasoning for + * [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently + * supported values are `low`, `medium`, and `high`. Reducing reasoning effort can + * result in faster responses and fewer tokens used on reasoning in a response. + */ + reasoning_effort?: 'low' | 'medium' | 'high' | null; + /** * Body param: Specifies the format that the model must output. Compatible with * [GPT-4o](https://platform.openai.com/docs/models#gpt-4o), @@ -823,11 +815,13 @@ export namespace RunCreateParams { /** * Set of 16 key-value pairs that can be attached to an object. This can be useful - * for storing additional information about the object in a structured format. Keys - * can be a maximum of 64 characters long and values can be a maxium of 512 - * characters long. + * for storing additional information about the object in a structured format, and + * querying for objects via API or the dashboard. + * + * Keys are strings with a maximum length of 64 characters. Values are strings with + * a maximum length of 512 characters. */ - metadata?: unknown | null; + metadata?: Shared.Metadata | null; } export namespace AdditionalMessage { @@ -895,14 +889,30 @@ export interface RunCreateParamsStreaming extends RunCreateParamsBase { stream: true; } +export interface RunRetrieveParams { + /** + * The ID of the [thread](https://platform.openai.com/docs/api-reference/threads) + * that was run. + */ + thread_id: string; +} + export interface RunUpdateParams { /** - * Set of 16 key-value pairs that can be attached to an object. This can be useful - * for storing additional information about the object in a structured format. Keys - * can be a maximum of 64 characters long and values can be a maxium of 512 - * characters long. + * Path param: The ID of the + * [thread](https://platform.openai.com/docs/api-reference/threads) that was run. + */ + thread_id: string; + + /** + * Body param: Set of 16 key-value pairs that can be attached to an object. This + * can be useful for storing additional information about the object in a + * structured format, and querying for objects via API or the dashboard. + * + * Keys are strings with a maximum length of 64 characters. Values are strings with + * a maximum length of 512 characters. */ - metadata?: unknown | null; + metadata?: Shared.Metadata | null; } export interface RunListParams extends CursorPageParams { @@ -921,629 +931,18 @@ export interface RunListParams extends CursorPageParams { order?: 'asc' | 'desc'; } -export interface RunCreateAndPollParams { - /** - * The ID of the - * [assistant](https://platform.openai.com/docs/api-reference/assistants) to use to - * execute this run. - */ - assistant_id: string; - - /** - * Appends additional instructions at the end of the instructions for the run. This - * is useful for modifying the behavior on a per-run basis without overriding other - * instructions. - */ - additional_instructions?: string | null; - - /** - * Adds additional messages to the thread before creating the run. - */ - additional_messages?: Array | null; - - /** - * Overrides the - * [instructions](https://platform.openai.com/docs/api-reference/assistants/createAssistant) - * of the assistant. This is useful for modifying the behavior on a per-run basis. - */ - instructions?: string | null; - - /** - * The maximum number of completion tokens that may be used over the course of the - * run. The run will make a best effort to use only the number of completion tokens - * specified, across multiple turns of the run. If the run exceeds the number of - * completion tokens specified, the run will end with status `incomplete`. See - * `incomplete_details` for more info. - */ - max_completion_tokens?: number | null; - - /** - * The maximum number of prompt tokens that may be used over the course of the run. - * The run will make a best effort to use only the number of prompt tokens - * specified, across multiple turns of the run. If the run exceeds the number of - * prompt tokens specified, the run will end with status `incomplete`. See - * `incomplete_details` for more info. - */ - max_prompt_tokens?: number | null; - - /** - * Set of 16 key-value pairs that can be attached to an object. This can be useful - * for storing additional information about the object in a structured format. Keys - * can be a maximum of 64 characters long and values can be a maxium of 512 - * characters long. - */ - metadata?: unknown | null; - - /** - * The ID of the [Model](https://platform.openai.com/docs/api-reference/models) to - * be used to execute this run. If a value is provided here, it will override the - * model associated with the assistant. If not, the model associated with the - * assistant will be used. - */ - model?: - | (string & {}) - | 'gpt-4o' - | 'gpt-4o-2024-05-13' - | 'gpt-4-turbo' - | 'gpt-4-turbo-2024-04-09' - | 'gpt-4-0125-preview' - | 'gpt-4-turbo-preview' - | 'gpt-4-1106-preview' - | 'gpt-4-vision-preview' - | 'gpt-4' - | 'gpt-4-0314' - | 'gpt-4-0613' - | 'gpt-4-32k' - | 'gpt-4-32k-0314' - | 'gpt-4-32k-0613' - | 'gpt-3.5-turbo' - | 'gpt-3.5-turbo-16k' - | 'gpt-3.5-turbo-0613' - | 'gpt-3.5-turbo-1106' - | 'gpt-3.5-turbo-0125' - | 'gpt-3.5-turbo-16k-0613' - | null; - - /** - * Specifies the format that the model must output. Compatible with - * [GPT-4o](https://platform.openai.com/docs/models/gpt-4o), - * [GPT-4 Turbo](https://platform.openai.com/docs/models/gpt-4-turbo-and-gpt-4), - * and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. - * - * Setting to `{ "type": "json_object" }` enables JSON mode, which guarantees the - * message the model generates is valid JSON. - * - * **Important:** when using JSON mode, you **must** also instruct the model to - * produce JSON yourself via a system or user message. Without this, the model may - * generate an unending stream of whitespace until the generation reaches the token - * limit, resulting in a long-running and seemingly "stuck" request. Also note that - * the message content may be partially cut off if `finish_reason="length"`, which - * indicates the generation exceeded `max_tokens` or the conversation exceeded the - * max context length. - */ - response_format?: ThreadsAPI.AssistantResponseFormatOption | null; - - /** - * What sampling temperature to use, between 0 and 2. Higher values like 0.8 will - * make the output more random, while lower values like 0.2 will make it more - * focused and deterministic. - */ - temperature?: number | null; - - /** - * Controls which (if any) tool is called by the model. `none` means the model will - * not call any tools and instead generates a message. `auto` is the default value - * and means the model can pick between generating a message or calling one or more - * tools. `required` means the model must call one or more tools before responding - * to the user. Specifying a particular tool like `{"type": "file_search"}` or - * `{"type": "function", "function": {"name": "my_function"}}` forces the model to - * call that tool. - */ - tool_choice?: ThreadsAPI.AssistantToolChoiceOption | null; - - /** - * Override the tools the assistant can use for this run. This is useful for - * modifying the behavior on a per-run basis. - */ - tools?: Array | null; - - /** - * An alternative to sampling with temperature, called nucleus sampling, where the - * model considers the results of the tokens with top_p probability mass. So 0.1 - * means only the tokens comprising the top 10% probability mass are considered. - * - * We generally recommend altering this or temperature but not both. - */ - top_p?: number | null; - - /** - * Controls for how a thread will be truncated prior to the run. Use this to - * control the intial context window of the run. - */ - truncation_strategy?: RunCreateAndPollParams.TruncationStrategy | null; -} - -export namespace RunCreateAndPollParams { - export interface AdditionalMessage { - /** - * The text contents of the message. - */ - content: string | Array; - - /** - * The role of the entity that is creating the message. Allowed values include: - * - * - `user`: Indicates the message is sent by an actual user and should be used in - * most cases to represent user-generated messages. - * - `assistant`: Indicates the message is generated by the assistant. Use this - * value to insert messages from the assistant into the conversation. - */ - role: 'user' | 'assistant'; - - /** - * A list of files attached to the message, and the tools they should be added to. - */ - attachments?: Array | null; - - /** - * Set of 16 key-value pairs that can be attached to an object. This can be useful - * for storing additional information about the object in a structured format. Keys - * can be a maximum of 64 characters long and values can be a maxium of 512 - * characters long. - */ - metadata?: unknown | null; - } - - export namespace AdditionalMessage { - export interface Attachment { - /** - * The ID of the file to attach to the message. - */ - file_id?: string; - - /** - * The tools to add this file to. - */ - tools?: Array; - } - } - - /** - * Controls for how a thread will be truncated prior to the run. Use this to - * control the intial context window of the run. - */ - export interface TruncationStrategy { - /** - * The truncation strategy to use for the thread. The default is `auto`. If set to - * `last_messages`, the thread will be truncated to the n most recent messages in - * the thread. When set to `auto`, messages in the middle of the thread will be - * dropped to fit the context length of the model, `max_prompt_tokens`. - */ - type: 'auto' | 'last_messages'; - - /** - * The number of most recent messages from the thread when constructing the context - * for the run. - */ - last_messages?: number | null; - } -} - -export interface RunCreateAndStreamParams { - /** - * The ID of the - * [assistant](https://platform.openai.com/docs/api-reference/assistants) to use to - * execute this run. - */ - assistant_id: string; - - /** - * Appends additional instructions at the end of the instructions for the run. This - * is useful for modifying the behavior on a per-run basis without overriding other - * instructions. - */ - additional_instructions?: string | null; - - /** - * Adds additional messages to the thread before creating the run. - */ - additional_messages?: Array | null; - - /** - * Overrides the - * [instructions](https://platform.openai.com/docs/api-reference/assistants/createAssistant) - * of the assistant. This is useful for modifying the behavior on a per-run basis. - */ - instructions?: string | null; - - /** - * The maximum number of completion tokens that may be used over the course of the - * run. The run will make a best effort to use only the number of completion tokens - * specified, across multiple turns of the run. If the run exceeds the number of - * completion tokens specified, the run will end with status `incomplete`. See - * `incomplete_details` for more info. - */ - max_completion_tokens?: number | null; - - /** - * The maximum number of prompt tokens that may be used over the course of the run. - * The run will make a best effort to use only the number of prompt tokens - * specified, across multiple turns of the run. If the run exceeds the number of - * prompt tokens specified, the run will end with status `incomplete`. See - * `incomplete_details` for more info. - */ - max_prompt_tokens?: number | null; - - /** - * Set of 16 key-value pairs that can be attached to an object. This can be useful - * for storing additional information about the object in a structured format. Keys - * can be a maximum of 64 characters long and values can be a maxium of 512 - * characters long. - */ - metadata?: unknown | null; - - /** - * The ID of the [Model](https://platform.openai.com/docs/api-reference/models) to - * be used to execute this run. If a value is provided here, it will override the - * model associated with the assistant. If not, the model associated with the - * assistant will be used. - */ - model?: - | (string & {}) - | 'gpt-4o' - | 'gpt-4o-2024-05-13' - | 'gpt-4-turbo' - | 'gpt-4-turbo-2024-04-09' - | 'gpt-4-0125-preview' - | 'gpt-4-turbo-preview' - | 'gpt-4-1106-preview' - | 'gpt-4-vision-preview' - | 'gpt-4' - | 'gpt-4-0314' - | 'gpt-4-0613' - | 'gpt-4-32k' - | 'gpt-4-32k-0314' - | 'gpt-4-32k-0613' - | 'gpt-3.5-turbo' - | 'gpt-3.5-turbo-16k' - | 'gpt-3.5-turbo-0613' - | 'gpt-3.5-turbo-1106' - | 'gpt-3.5-turbo-0125' - | 'gpt-3.5-turbo-16k-0613' - | null; - - /** - * Specifies the format that the model must output. Compatible with - * [GPT-4o](https://platform.openai.com/docs/models/gpt-4o), - * [GPT-4 Turbo](https://platform.openai.com/docs/models/gpt-4-turbo-and-gpt-4), - * and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. - * - * Setting to `{ "type": "json_object" }` enables JSON mode, which guarantees the - * message the model generates is valid JSON. - * - * **Important:** when using JSON mode, you **must** also instruct the model to - * produce JSON yourself via a system or user message. Without this, the model may - * generate an unending stream of whitespace until the generation reaches the token - * limit, resulting in a long-running and seemingly "stuck" request. Also note that - * the message content may be partially cut off if `finish_reason="length"`, which - * indicates the generation exceeded `max_tokens` or the conversation exceeded the - * max context length. - */ - response_format?: ThreadsAPI.AssistantResponseFormatOption | null; - - /** - * What sampling temperature to use, between 0 and 2. Higher values like 0.8 will - * make the output more random, while lower values like 0.2 will make it more - * focused and deterministic. - */ - temperature?: number | null; - - /** - * Controls which (if any) tool is called by the model. `none` means the model will - * not call any tools and instead generates a message. `auto` is the default value - * and means the model can pick between generating a message or calling one or more - * tools. `required` means the model must call one or more tools before responding - * to the user. Specifying a particular tool like `{"type": "file_search"}` or - * `{"type": "function", "function": {"name": "my_function"}}` forces the model to - * call that tool. - */ - tool_choice?: ThreadsAPI.AssistantToolChoiceOption | null; - - /** - * Override the tools the assistant can use for this run. This is useful for - * modifying the behavior on a per-run basis. - */ - tools?: Array | null; - - /** - * An alternative to sampling with temperature, called nucleus sampling, where the - * model considers the results of the tokens with top_p probability mass. So 0.1 - * means only the tokens comprising the top 10% probability mass are considered. - * - * We generally recommend altering this or temperature but not both. - */ - top_p?: number | null; - - /** - * Controls for how a thread will be truncated prior to the run. Use this to - * control the intial context window of the run. - */ - truncation_strategy?: RunCreateAndStreamParams.TruncationStrategy | null; -} - -export namespace RunCreateAndStreamParams { - export interface AdditionalMessage { - /** - * The text contents of the message. - */ - content: string | Array; - - /** - * The role of the entity that is creating the message. Allowed values include: - * - * - `user`: Indicates the message is sent by an actual user and should be used in - * most cases to represent user-generated messages. - * - `assistant`: Indicates the message is generated by the assistant. Use this - * value to insert messages from the assistant into the conversation. - */ - role: 'user' | 'assistant'; - - /** - * A list of files attached to the message, and the tools they should be added to. - */ - attachments?: Array | null; - - /** - * Set of 16 key-value pairs that can be attached to an object. This can be useful - * for storing additional information about the object in a structured format. Keys - * can be a maximum of 64 characters long and values can be a maxium of 512 - * characters long. - */ - metadata?: unknown | null; - } - - export namespace AdditionalMessage { - export interface Attachment { - /** - * The ID of the file to attach to the message. - */ - file_id?: string; - - /** - * The tools to add this file to. - */ - tools?: Array; - } - } - - /** - * Controls for how a thread will be truncated prior to the run. Use this to - * control the intial context window of the run. - */ - export interface TruncationStrategy { - /** - * The truncation strategy to use for the thread. The default is `auto`. If set to - * `last_messages`, the thread will be truncated to the n most recent messages in - * the thread. When set to `auto`, messages in the middle of the thread will be - * dropped to fit the context length of the model, `max_prompt_tokens`. - */ - type: 'auto' | 'last_messages'; - - /** - * The number of most recent messages from the thread when constructing the context - * for the run. - */ - last_messages?: number | null; - } -} - -export interface RunStreamParams { - /** - * The ID of the - * [assistant](https://platform.openai.com/docs/api-reference/assistants) to use to - * execute this run. - */ - assistant_id: string; - - /** - * Appends additional instructions at the end of the instructions for the run. This - * is useful for modifying the behavior on a per-run basis without overriding other - * instructions. - */ - additional_instructions?: string | null; - - /** - * Adds additional messages to the thread before creating the run. - */ - additional_messages?: Array | null; - - /** - * Overrides the - * [instructions](https://platform.openai.com/docs/api-reference/assistants/createAssistant) - * of the assistant. This is useful for modifying the behavior on a per-run basis. - */ - instructions?: string | null; - - /** - * The maximum number of completion tokens that may be used over the course of the - * run. The run will make a best effort to use only the number of completion tokens - * specified, across multiple turns of the run. If the run exceeds the number of - * completion tokens specified, the run will end with status `incomplete`. See - * `incomplete_details` for more info. - */ - max_completion_tokens?: number | null; - - /** - * The maximum number of prompt tokens that may be used over the course of the run. - * The run will make a best effort to use only the number of prompt tokens - * specified, across multiple turns of the run. If the run exceeds the number of - * prompt tokens specified, the run will end with status `incomplete`. See - * `incomplete_details` for more info. - */ - max_prompt_tokens?: number | null; - - /** - * Set of 16 key-value pairs that can be attached to an object. This can be useful - * for storing additional information about the object in a structured format. Keys - * can be a maximum of 64 characters long and values can be a maxium of 512 - * characters long. - */ - metadata?: unknown | null; - - /** - * The ID of the [Model](https://platform.openai.com/docs/api-reference/models) to - * be used to execute this run. If a value is provided here, it will override the - * model associated with the assistant. If not, the model associated with the - * assistant will be used. - */ - model?: - | (string & {}) - | 'gpt-4o' - | 'gpt-4o-2024-05-13' - | 'gpt-4-turbo' - | 'gpt-4-turbo-2024-04-09' - | 'gpt-4-0125-preview' - | 'gpt-4-turbo-preview' - | 'gpt-4-1106-preview' - | 'gpt-4-vision-preview' - | 'gpt-4' - | 'gpt-4-0314' - | 'gpt-4-0613' - | 'gpt-4-32k' - | 'gpt-4-32k-0314' - | 'gpt-4-32k-0613' - | 'gpt-3.5-turbo' - | 'gpt-3.5-turbo-16k' - | 'gpt-3.5-turbo-0613' - | 'gpt-3.5-turbo-1106' - | 'gpt-3.5-turbo-0125' - | 'gpt-3.5-turbo-16k-0613' - | null; - - /** - * Specifies the format that the model must output. Compatible with - * [GPT-4o](https://platform.openai.com/docs/models/gpt-4o), - * [GPT-4 Turbo](https://platform.openai.com/docs/models/gpt-4-turbo-and-gpt-4), - * and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. - * - * Setting to `{ "type": "json_object" }` enables JSON mode, which guarantees the - * message the model generates is valid JSON. - * - * **Important:** when using JSON mode, you **must** also instruct the model to - * produce JSON yourself via a system or user message. Without this, the model may - * generate an unending stream of whitespace until the generation reaches the token - * limit, resulting in a long-running and seemingly "stuck" request. Also note that - * the message content may be partially cut off if `finish_reason="length"`, which - * indicates the generation exceeded `max_tokens` or the conversation exceeded the - * max context length. - */ - response_format?: ThreadsAPI.AssistantResponseFormatOption | null; - - /** - * What sampling temperature to use, between 0 and 2. Higher values like 0.8 will - * make the output more random, while lower values like 0.2 will make it more - * focused and deterministic. - */ - temperature?: number | null; - - /** - * Controls which (if any) tool is called by the model. `none` means the model will - * not call any tools and instead generates a message. `auto` is the default value - * and means the model can pick between generating a message or calling one or more - * tools. `required` means the model must call one or more tools before responding - * to the user. Specifying a particular tool like `{"type": "file_search"}` or - * `{"type": "function", "function": {"name": "my_function"}}` forces the model to - * call that tool. - */ - tool_choice?: ThreadsAPI.AssistantToolChoiceOption | null; - - /** - * Override the tools the assistant can use for this run. This is useful for - * modifying the behavior on a per-run basis. - */ - tools?: Array | null; - - /** - * An alternative to sampling with temperature, called nucleus sampling, where the - * model considers the results of the tokens with top_p probability mass. So 0.1 - * means only the tokens comprising the top 10% probability mass are considered. - * - * We generally recommend altering this or temperature but not both. - */ - top_p?: number | null; - +export interface RunCancelParams { /** - * Controls for how a thread will be truncated prior to the run. Use this to - * control the intial context window of the run. + * The ID of the thread to which this run belongs. */ - truncation_strategy?: RunStreamParams.TruncationStrategy | null; + thread_id: string; } -export namespace RunStreamParams { - export interface AdditionalMessage { - /** - * The text contents of the message. - */ - content: string | Array; - - /** - * The role of the entity that is creating the message. Allowed values include: - * - * - `user`: Indicates the message is sent by an actual user and should be used in - * most cases to represent user-generated messages. - * - `assistant`: Indicates the message is generated by the assistant. Use this - * value to insert messages from the assistant into the conversation. - */ - role: 'user' | 'assistant'; - - /** - * A list of files attached to the message, and the tools they should be added to. - */ - attachments?: Array | null; - - /** - * Set of 16 key-value pairs that can be attached to an object. This can be useful - * for storing additional information about the object in a structured format. Keys - * can be a maximum of 64 characters long and values can be a maxium of 512 - * characters long. - */ - metadata?: unknown | null; - } +export type RunCreateAndPollParams = ThreadsAPI.ThreadCreateAndRunParamsNonStreaming; - export namespace AdditionalMessage { - export interface Attachment { - /** - * The ID of the file to attach to the message. - */ - file_id?: string; +export type RunCreateAndStreamParams = RunCreateParamsBaseStream; - /** - * The tools to add this file to. - */ - tools?: Array; - } - } - - /** - * Controls for how a thread will be truncated prior to the run. Use this to - * control the intial context window of the run. - */ - export interface TruncationStrategy { - /** - * The truncation strategy to use for the thread. The default is `auto`. If set to - * `last_messages`, the thread will be truncated to the n most recent messages in - * the thread. When set to `auto`, messages in the middle of the thread will be - * dropped to fit the context length of the model, `max_prompt_tokens`. - */ - type: 'auto' | 'last_messages'; - - /** - * The number of most recent messages from the thread when constructing the context - * for the run. - */ - last_messages?: number | null; - } -} +export type RunStreamParams = RunCreateParamsBaseStream; export type RunSubmitToolOutputsParams = | RunSubmitToolOutputsParamsNonStreaming @@ -1551,14 +950,21 @@ export type RunSubmitToolOutputsParams = export interface RunSubmitToolOutputsParamsBase { /** - * A list of tools for which the outputs are being submitted. + * Path param: The ID of the + * [thread](https://platform.openai.com/docs/api-reference/threads) to which this + * run belongs. + */ + thread_id: string; + + /** + * Body param: A list of tools for which the outputs are being submitted. */ tool_outputs: Array; /** - * If `true`, returns a stream of events that happen during the Run as server-sent - * events, terminating when the Run enters a terminal state with a `data: [DONE]` - * message. + * Body param: If `true`, returns a stream of events that happen during the Run as + * server-sent events, terminating when the Run enters a terminal state with a + * `data: [DONE]` message. */ stream?: boolean | null; } @@ -1583,79 +989,37 @@ export namespace RunSubmitToolOutputsParams { export interface RunSubmitToolOutputsParamsNonStreaming extends RunSubmitToolOutputsParamsBase { /** - * If `true`, returns a stream of events that happen during the Run as server-sent - * events, terminating when the Run enters a terminal state with a `data: [DONE]` - * message. + * Body param: If `true`, returns a stream of events that happen during the Run as + * server-sent events, terminating when the Run enters a terminal state with a + * `data: [DONE]` message. */ stream?: false | null; } export interface RunSubmitToolOutputsParamsStreaming extends RunSubmitToolOutputsParamsBase { /** - * If `true`, returns a stream of events that happen during the Run as server-sent - * events, terminating when the Run enters a terminal state with a `data: [DONE]` - * message. + * Body param: If `true`, returns a stream of events that happen during the Run as + * server-sent events, terminating when the Run enters a terminal state with a + * `data: [DONE]` message. */ stream: true; } -export interface RunSubmitToolOutputsAndPollParams { - /** - * A list of tools for which the outputs are being submitted. - */ - tool_outputs: Array; -} - -export namespace RunSubmitToolOutputsAndPollParams { - export interface ToolOutput { - /** - * The output of the tool call to be submitted to continue the run. - */ - output?: string; - - /** - * The ID of the tool call in the `required_action` object within the run object - * the output is being submitted for. - */ - tool_call_id?: string; - } -} - -export interface RunSubmitToolOutputsStreamParams { - /** - * A list of tools for which the outputs are being submitted. - */ - tool_outputs: Array; -} - -export namespace RunSubmitToolOutputsStreamParams { - export interface ToolOutput { - /** - * The output of the tool call to be submitted to continue the run. - */ - output?: string; - - /** - * The ID of the tool call in the `required_action` object within the run object - * the output is being submitted for. - */ - tool_call_id?: string; - } -} +export type RunSubmitToolOutputsAndPollParams = RunSubmitToolOutputsParamsNonStreaming; +export type RunSubmitToolOutputsStreamParams = RunSubmitToolOutputsParamsStream; -Runs.RunsPage = RunsPage; Runs.Steps = Steps; -Runs.RunStepsPage = RunStepsPage; export declare namespace Runs { export { type RequiredActionFunctionToolCall as RequiredActionFunctionToolCall, type Run as Run, type RunStatus as RunStatus, - RunsPage as RunsPage, + type RunsPage as RunsPage, type RunCreateParams as RunCreateParams, type RunCreateParamsNonStreaming as RunCreateParamsNonStreaming, type RunCreateParamsStreaming as RunCreateParamsStreaming, + type RunRetrieveParams as RunRetrieveParams, type RunUpdateParams as RunUpdateParams, type RunListParams as RunListParams, type RunCreateAndPollParams, @@ -1688,7 +1052,7 @@ export declare namespace Runs { type ToolCallDelta as ToolCallDelta, type ToolCallDeltaObject as ToolCallDeltaObject, type ToolCallsStepDetails as ToolCallsStepDetails, - RunStepsPage as RunStepsPage, + type RunStepsPage as RunStepsPage, type StepRetrieveParams as StepRetrieveParams, type StepListParams as StepListParams, }; diff --git a/src/resources/beta/threads/runs/steps.ts b/src/resources/beta/threads/runs/steps.ts index 6c6722b62..adaa4c9a1 100644 --- a/src/resources/beta/threads/runs/steps.ts +++ b/src/resources/beta/threads/runs/steps.ts @@ -1,77 +1,41 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import { APIResource } from '../../../../resource'; -import { isRequestOptions } from '../../../../core'; -import * as Core from '../../../../core'; import * as StepsAPI from './steps'; -import { CursorPage, type CursorPageParams } from '../../../../pagination'; +import * as Shared from '../../../shared'; +import { APIPromise } from '../../../../api-promise'; +import { CursorPage, type CursorPageParams, PagePromise } from '../../../../pagination'; +import { buildHeaders } from '../../../../internal/headers'; +import { RequestOptions } from '../../../../internal/request-options'; +import { path } from '../../../../internal/utils/path'; export class Steps extends APIResource { /** * Retrieves a run step. */ - retrieve( - threadId: string, - runId: string, - stepId: string, - query?: StepRetrieveParams, - options?: Core.RequestOptions, - ): Core.APIPromise; - retrieve( - threadId: string, - runId: string, - stepId: string, - options?: Core.RequestOptions, - ): Core.APIPromise; - retrieve( - threadId: string, - runId: string, - stepId: string, - query: StepRetrieveParams | Core.RequestOptions = {}, - options?: Core.RequestOptions, - ): Core.APIPromise { - if (isRequestOptions(query)) { - return this.retrieve(threadId, runId, stepId, {}, query); - } - return this._client.get(`/threads/${threadId}/runs/${runId}/steps/${stepId}`, { + retrieve(stepID: string, params: StepRetrieveParams, options?: RequestOptions): APIPromise { + const { thread_id, run_id, ...query } = params; + return this._client.get(path`/threads/${thread_id}/runs/${run_id}/steps/${stepID}`, { query, ...options, - headers: { 'OpenAI-Beta': 'assistants=v2', ...options?.headers }, + headers: buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), }); } /** * Returns a list of run steps belonging to a run. */ - list( - threadId: string, - runId: string, - query?: StepListParams, - options?: Core.RequestOptions, - ): Core.PagePromise; - list( - threadId: string, - runId: string, - options?: Core.RequestOptions, - ): Core.PagePromise; - list( - threadId: string, - runId: string, - query: StepListParams | Core.RequestOptions = {}, - options?: Core.RequestOptions, - ): Core.PagePromise { - if (isRequestOptions(query)) { - return this.list(threadId, runId, {}, query); - } - return this._client.getAPIList(`/threads/${threadId}/runs/${runId}/steps`, RunStepsPage, { + list(runID: string, params: StepListParams, options?: RequestOptions): PagePromise { + const { thread_id, ...query } = params; + return this._client.getAPIList(path`/threads/${thread_id}/runs/${runID}/steps`, CursorPage, { query, ...options, - headers: { 'OpenAI-Beta': 'assistants=v2', ...options?.headers }, + headers: buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), }); } } -export class RunStepsPage extends CursorPage {} +export type RunStepsPage = CursorPage; /** * Text output from the Code Interpreter tool call as part of a run step. @@ -515,11 +479,13 @@ export interface RunStep { /** * Set of 16 key-value pairs that can be attached to an object. This can be useful - * for storing additional information about the object in a structured format. Keys - * can be a maximum of 64 characters long and values can be a maxium of 512 - * characters long. + * for storing additional information about the object in a structured format, and + * querying for objects via API or the dashboard. + * + * Keys are strings with a maximum length of 64 characters. Values are strings with + * a maximum length of 512 characters. */ - metadata: unknown | null; + metadata: Shared.Metadata | null; /** * The object type, which is always `thread.run.step`. @@ -700,9 +666,20 @@ export interface ToolCallsStepDetails { export interface StepRetrieveParams { /** - * A list of additional fields to include in the response. Currently the only - * supported value is `step_details.tool_calls[*].file_search.results[*].content` - * to fetch the file search result content. + * Path param: The ID of the thread to which the run and run step belongs. + */ + thread_id: string; + + /** + * Path param: The ID of the run to which the run step belongs. + */ + run_id: string; + + /** + * Query param: A list of additional fields to include in the response. Currently + * the only supported value is + * `step_details.tool_calls[*].file_search.results[*].content` to fetch the file + * search result content. * * See the * [file search tool documentation](https://platform.openai.com/docs/assistants/tools/file-search#customizing-file-search-settings) @@ -713,17 +690,23 @@ export interface StepRetrieveParams { export interface StepListParams extends CursorPageParams { /** - * A cursor for use in pagination. `before` is an object ID that defines your place - * in the list. For instance, if you make a list request and receive 100 objects, - * starting with obj_foo, your subsequent call can include before=obj_foo in order - * to fetch the previous page of the list. + * Path param: The ID of the thread the run and run steps belong to. + */ + thread_id: string; + + /** + * Query param: A cursor for use in pagination. `before` is an object ID that + * defines your place in the list. For instance, if you make a list request and + * receive 100 objects, starting with obj_foo, your subsequent call can include + * before=obj_foo in order to fetch the previous page of the list. */ before?: string; /** - * A list of additional fields to include in the response. Currently the only - * supported value is `step_details.tool_calls[*].file_search.results[*].content` - * to fetch the file search result content. + * Query param: A list of additional fields to include in the response. Currently + * the only supported value is + * `step_details.tool_calls[*].file_search.results[*].content` to fetch the file + * search result content. * * See the * [file search tool documentation](https://platform.openai.com/docs/assistants/tools/file-search#customizing-file-search-settings) @@ -732,14 +715,12 @@ export interface StepListParams extends CursorPageParams { include?: Array; /** - * Sort order by the `created_at` timestamp of the objects. `asc` for ascending - * order and `desc` for descending order. + * Query param: Sort order by the `created_at` timestamp of the objects. `asc` for + * ascending order and `desc` for descending order. */ order?: 'asc' | 'desc'; } -Steps.RunStepsPage = RunStepsPage; - export declare namespace Steps { export { type CodeInterpreterLogs as CodeInterpreterLogs, @@ -760,7 +741,7 @@ export declare namespace Steps { type ToolCallDelta as ToolCallDelta, type ToolCallDeltaObject as ToolCallDeltaObject, type ToolCallsStepDetails as ToolCallsStepDetails, - RunStepsPage as RunStepsPage, + type RunStepsPage as RunStepsPage, type StepRetrieveParams as StepRetrieveParams, type StepListParams as StepListParams, }; diff --git a/src/resources/beta/threads/threads.ts b/src/resources/beta/threads/threads.ts index 453d8fa10..be1014f68 100644 --- a/src/resources/beta/threads/threads.ts +++ b/src/resources/beta/threads/threads.ts @@ -1,10 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import { APIResource } from '../../../resource'; -import { isRequestOptions } from '../../../core'; -import { AssistantStream, ThreadCreateAndRunParamsBaseStream } from '../../../lib/AssistantStream'; -import { APIPromise } from '../../../core'; -import * as Core from '../../../core'; import * as ThreadsAPI from './threads'; import * as Shared from '../../shared'; import * as AssistantsAPI from '../assistants'; @@ -30,10 +26,12 @@ import { MessageContentDelta, MessageContentPartParam, MessageCreateParams, + MessageDeleteParams, MessageDeleted, MessageDelta, MessageDeltaEvent, MessageListParams, + MessageRetrieveParams, MessageUpdateParams, Messages, MessagesPage, @@ -52,10 +50,12 @@ import { Run, RunCreateAndPollParams, RunCreateAndStreamParams, + RunCancelParams, RunCreateParams, RunCreateParamsNonStreaming, RunCreateParamsStreaming, RunListParams, + RunRetrieveParams, RunStatus, RunStreamParams, RunSubmitToolOutputsAndPollParams, @@ -67,7 +67,12 @@ import { Runs, RunsPage, } from './runs/runs'; +import { APIPromise } from '../../../api-promise'; import { Stream } from '../../../streaming'; +import { buildHeaders } from '../../../internal/headers'; +import { RequestOptions } from '../../../internal/request-options'; +import { AssistantStream, ThreadCreateAndRunParamsBaseStream } from '../../../lib/AssistantStream'; +import { path } from '../../../internal/utils/path'; export class Threads extends APIResource { runs: RunsAPI.Runs = new RunsAPI.Runs(this._client); @@ -76,76 +81,65 @@ export class Threads extends APIResource { /** * Create a thread. */ - create(body?: ThreadCreateParams, options?: Core.RequestOptions): Core.APIPromise; - create(options?: Core.RequestOptions): Core.APIPromise; - create( - body: ThreadCreateParams | Core.RequestOptions = {}, - options?: Core.RequestOptions, - ): Core.APIPromise { - if (isRequestOptions(body)) { - return this.create({}, body); - } + create(body: ThreadCreateParams | null | undefined = {}, options?: RequestOptions): APIPromise { return this._client.post('/threads', { body, ...options, - headers: { 'OpenAI-Beta': 'assistants=v2', ...options?.headers }, + headers: buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), }); } /** * Retrieves a thread. */ - retrieve(threadId: string, options?: Core.RequestOptions): Core.APIPromise { - return this._client.get(`/threads/${threadId}`, { + retrieve(threadID: string, options?: RequestOptions): APIPromise { + return this._client.get(path`/threads/${threadID}`, { ...options, - headers: { 'OpenAI-Beta': 'assistants=v2', ...options?.headers }, + headers: buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), }); } /** * Modifies a thread. */ - update(threadId: string, body: ThreadUpdateParams, options?: Core.RequestOptions): Core.APIPromise { - return this._client.post(`/threads/${threadId}`, { + update(threadID: string, body: ThreadUpdateParams, options?: RequestOptions): APIPromise { + return this._client.post(path`/threads/${threadID}`, { body, ...options, - headers: { 'OpenAI-Beta': 'assistants=v2', ...options?.headers }, + headers: buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), }); } /** * Delete a thread. */ - del(threadId: string, options?: Core.RequestOptions): Core.APIPromise { - return this._client.delete(`/threads/${threadId}`, { + delete(threadID: string, options?: RequestOptions): APIPromise { + return this._client.delete(path`/threads/${threadID}`, { ...options, - headers: { 'OpenAI-Beta': 'assistants=v2', ...options?.headers }, + headers: buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), }); } /** * Create a thread and run it in one request. */ - createAndRun( - body: ThreadCreateAndRunParamsNonStreaming, - options?: Core.RequestOptions, - ): APIPromise; + createAndRun(body: ThreadCreateAndRunParamsNonStreaming, options?: RequestOptions): APIPromise; createAndRun( body: ThreadCreateAndRunParamsStreaming, - options?: Core.RequestOptions, + options?: RequestOptions, ): APIPromise>; createAndRun( body: ThreadCreateAndRunParamsBase, - options?: Core.RequestOptions, + options?: RequestOptions, ): APIPromise | RunsAPI.Run>; createAndRun( body: ThreadCreateAndRunParams, - options?: Core.RequestOptions, + options?: RequestOptions, ): APIPromise | APIPromise> { return this._client.post('/threads/runs', { body, ...options, - headers: { 'OpenAI-Beta': 'assistants=v2', ...options?.headers }, + headers: buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), stream: body.stream ?? false, }) as APIPromise | APIPromise>; } @@ -157,19 +151,16 @@ export class Threads extends APIResource { */ async createAndRunPoll( body: ThreadCreateAndRunParamsNonStreaming, - options?: Core.RequestOptions & { pollIntervalMs?: number }, + options?: RequestOptions & { pollIntervalMs?: number }, ): Promise { const run = await this.createAndRun(body, options); - return await this.runs.poll(run.thread_id, run.id, options); + return await this.runs.poll(run.id, { thread_id: run.thread_id }, options); } /** * Create a thread and stream the run back */ - createAndRunStream( - body: ThreadCreateAndRunParamsBaseStream, - options?: Core.RequestOptions, - ): AssistantStream { + createAndRunStream(body: ThreadCreateAndRunParamsBaseStream, options?: RequestOptions): AssistantStream { return AssistantStream.createThreadAssistantStream(body, this._client.beta.threads, options); } } @@ -250,11 +241,13 @@ export interface Thread { /** * Set of 16 key-value pairs that can be attached to an object. This can be useful - * for storing additional information about the object in a structured format. Keys - * can be a maximum of 64 characters long and values can be a maxium of 512 - * characters long. + * for storing additional information about the object in a structured format, and + * querying for objects via API or the dashboard. + * + * Keys are strings with a maximum length of 64 characters. Values are strings with + * a maximum length of 512 characters. */ - metadata: unknown | null; + metadata: Shared.Metadata | null; /** * The object type, which is always `thread`. @@ -322,11 +315,13 @@ export interface ThreadCreateParams { /** * Set of 16 key-value pairs that can be attached to an object. This can be useful - * for storing additional information about the object in a structured format. Keys - * can be a maximum of 64 characters long and values can be a maxium of 512 - * characters long. + * for storing additional information about the object in a structured format, and + * querying for objects via API or the dashboard. + * + * Keys are strings with a maximum length of 64 characters. Values are strings with + * a maximum length of 512 characters. */ - metadata?: unknown | null; + metadata?: Shared.Metadata | null; /** * A set of resources that are made available to the assistant's tools in this @@ -361,11 +356,13 @@ export namespace ThreadCreateParams { /** * Set of 16 key-value pairs that can be attached to an object. This can be useful - * for storing additional information about the object in a structured format. Keys - * can be a maximum of 64 characters long and values can be a maxium of 512 - * characters long. + * for storing additional information about the object in a structured format, and + * querying for objects via API or the dashboard. + * + * Keys are strings with a maximum length of 64 characters. Values are strings with + * a maximum length of 512 characters. */ - metadata?: unknown | null; + metadata?: Shared.Metadata | null; } export namespace Message { @@ -447,12 +444,14 @@ export namespace ThreadCreateParams { file_ids?: Array; /** - * Set of 16 key-value pairs that can be attached to a vector store. This can be - * useful for storing additional information about the vector store in a structured - * format. Keys can be a maximum of 64 characters long and values can be a maxium - * of 512 characters long. + * Set of 16 key-value pairs that can be attached to an object. This can be useful + * for storing additional information about the object in a structured format, and + * querying for objects via API or the dashboard. + * + * Keys are strings with a maximum length of 64 characters. Values are strings with + * a maximum length of 512 characters. */ - metadata?: unknown; + metadata?: Shared.Metadata | null; } } } @@ -461,11 +460,13 @@ export namespace ThreadCreateParams { export interface ThreadUpdateParams { /** * Set of 16 key-value pairs that can be attached to an object. This can be useful - * for storing additional information about the object in a structured format. Keys - * can be a maximum of 64 characters long and values can be a maxium of 512 - * characters long. + * for storing additional information about the object in a structured format, and + * querying for objects via API or the dashboard. + * + * Keys are strings with a maximum length of 64 characters. Values are strings with + * a maximum length of 512 characters. */ - metadata?: unknown | null; + metadata?: Shared.Metadata | null; /** * A set of resources that are made available to the assistant's tools in this @@ -549,11 +550,13 @@ export interface ThreadCreateAndRunParamsBase { /** * Set of 16 key-value pairs that can be attached to an object. This can be useful - * for storing additional information about the object in a structured format. Keys - * can be a maximum of 64 characters long and values can be a maxium of 512 - * characters long. + * for storing additional information about the object in a structured format, and + * querying for objects via API or the dashboard. + * + * Keys are strings with a maximum length of 64 characters. Values are strings with + * a maximum length of 512 characters. */ - metadata?: unknown | null; + metadata?: Shared.Metadata | null; /** * The ID of the [Model](https://platform.openai.com/docs/api-reference/models) to @@ -609,7 +612,8 @@ export interface ThreadCreateAndRunParamsBase { temperature?: number | null; /** - * If no thread is provided, an empty thread will be created. + * Options to create a new thread. If no thread is provided when running a request, + * an empty thread will be created. */ thread?: ThreadCreateAndRunParams.Thread; @@ -658,7 +662,8 @@ export interface ThreadCreateAndRunParamsBase { export namespace ThreadCreateAndRunParams { /** - * If no thread is provided, an empty thread will be created. + * Options to create a new thread. If no thread is provided when running a request, + * an empty thread will be created. */ export interface Thread { /** @@ -669,11 +674,13 @@ export namespace ThreadCreateAndRunParams { /** * Set of 16 key-value pairs that can be attached to an object. This can be useful - * for storing additional information about the object in a structured format. Keys - * can be a maximum of 64 characters long and values can be a maxium of 512 - * characters long. + * for storing additional information about the object in a structured format, and + * querying for objects via API or the dashboard. + * + * Keys are strings with a maximum length of 64 characters. Values are strings with + * a maximum length of 512 characters. */ - metadata?: unknown | null; + metadata?: Shared.Metadata | null; /** * A set of resources that are made available to the assistant's tools in this @@ -708,11 +715,13 @@ export namespace ThreadCreateAndRunParams { /** * Set of 16 key-value pairs that can be attached to an object. This can be useful - * for storing additional information about the object in a structured format. Keys - * can be a maximum of 64 characters long and values can be a maxium of 512 - * characters long. + * for storing additional information about the object in a structured format, and + * querying for objects via API or the dashboard. + * + * Keys are strings with a maximum length of 64 characters. Values are strings with + * a maximum length of 512 characters. */ - metadata?: unknown | null; + metadata?: Shared.Metadata | null; } export namespace Message { @@ -794,12 +803,14 @@ export namespace ThreadCreateAndRunParams { file_ids?: Array; /** - * Set of 16 key-value pairs that can be attached to a vector store. This can be - * useful for storing additional information about the vector store in a structured - * format. Keys can be a maximum of 64 characters long and values can be a maxium - * of 512 characters long. + * Set of 16 key-value pairs that can be attached to an object. This can be useful + * for storing additional information about the object in a structured format, and + * querying for objects via API or the dashboard. + * + * Keys are strings with a maximum length of 64 characters. Values are strings with + * a maximum length of 512 characters. */ - metadata?: unknown; + metadata?: Shared.Metadata | null; } } } @@ -1212,342 +1223,10 @@ export namespace ThreadCreateAndRunPollParams { } } -export interface ThreadCreateAndRunStreamParams { - /** - * The ID of the - * [assistant](https://platform.openai.com/docs/api-reference/assistants) to use to - * execute this run. - */ - assistant_id: string; - - /** - * Override the default system message of the assistant. This is useful for - * modifying the behavior on a per-run basis. - */ - instructions?: string | null; - - /** - * The maximum number of completion tokens that may be used over the course of the - * run. The run will make a best effort to use only the number of completion tokens - * specified, across multiple turns of the run. If the run exceeds the number of - * completion tokens specified, the run will end with status `incomplete`. See - * `incomplete_details` for more info. - */ - max_completion_tokens?: number | null; - - /** - * The maximum number of prompt tokens that may be used over the course of the run. - * The run will make a best effort to use only the number of prompt tokens - * specified, across multiple turns of the run. If the run exceeds the number of - * prompt tokens specified, the run will end with status `incomplete`. See - * `incomplete_details` for more info. - */ - max_prompt_tokens?: number | null; - - /** - * Set of 16 key-value pairs that can be attached to an object. This can be useful - * for storing additional information about the object in a structured format. Keys - * can be a maximum of 64 characters long and values can be a maxium of 512 - * characters long. - */ - metadata?: unknown | null; - - /** - * The ID of the [Model](https://platform.openai.com/docs/api-reference/models) to - * be used to execute this run. If a value is provided here, it will override the - * model associated with the assistant. If not, the model associated with the - * assistant will be used. - */ - model?: - | (string & {}) - | 'gpt-4o' - | 'gpt-4o-2024-05-13' - | 'gpt-4-turbo' - | 'gpt-4-turbo-2024-04-09' - | 'gpt-4-0125-preview' - | 'gpt-4-turbo-preview' - | 'gpt-4-1106-preview' - | 'gpt-4-vision-preview' - | 'gpt-4' - | 'gpt-4-0314' - | 'gpt-4-0613' - | 'gpt-4-32k' - | 'gpt-4-32k-0314' - | 'gpt-4-32k-0613' - | 'gpt-3.5-turbo' - | 'gpt-3.5-turbo-16k' - | 'gpt-3.5-turbo-0613' - | 'gpt-3.5-turbo-1106' - | 'gpt-3.5-turbo-0125' - | 'gpt-3.5-turbo-16k-0613' - | null; - - /** - * Specifies the format that the model must output. Compatible with - * [GPT-4o](https://platform.openai.com/docs/models/gpt-4o), - * [GPT-4 Turbo](https://platform.openai.com/docs/models/gpt-4-turbo-and-gpt-4), - * and all GPT-3.5 Turbo models since `gpt-3.5-turbo-1106`. - * - * Setting to `{ "type": "json_object" }` enables JSON mode, which guarantees the - * message the model generates is valid JSON. - * - * **Important:** when using JSON mode, you **must** also instruct the model to - * produce JSON yourself via a system or user message. Without this, the model may - * generate an unending stream of whitespace until the generation reaches the token - * limit, resulting in a long-running and seemingly "stuck" request. Also note that - * the message content may be partially cut off if `finish_reason="length"`, which - * indicates the generation exceeded `max_tokens` or the conversation exceeded the - * max context length. - */ - response_format?: AssistantResponseFormatOption | null; - - /** - * What sampling temperature to use, between 0 and 2. Higher values like 0.8 will - * make the output more random, while lower values like 0.2 will make it more - * focused and deterministic. - */ - temperature?: number | null; - - /** - * If no thread is provided, an empty thread will be created. - */ - thread?: ThreadCreateAndRunStreamParams.Thread; - - /** - * Controls which (if any) tool is called by the model. `none` means the model will - * not call any tools and instead generates a message. `auto` is the default value - * and means the model can pick between generating a message or calling one or more - * tools. `required` means the model must call one or more tools before responding - * to the user. Specifying a particular tool like `{"type": "file_search"}` or - * `{"type": "function", "function": {"name": "my_function"}}` forces the model to - * call that tool. - */ - tool_choice?: AssistantToolChoiceOption | null; - - /** - * A set of resources that are used by the assistant's tools. The resources are - * specific to the type of tool. For example, the `code_interpreter` tool requires - * a list of file IDs, while the `file_search` tool requires a list of vector store - * IDs. - */ - tool_resources?: ThreadCreateAndRunStreamParams.ToolResources | null; - - /** - * Override the tools the assistant can use for this run. This is useful for - * modifying the behavior on a per-run basis. - */ - tools?: Array< - AssistantsAPI.CodeInterpreterTool | AssistantsAPI.FileSearchTool | AssistantsAPI.FunctionTool - > | null; - - /** - * An alternative to sampling with temperature, called nucleus sampling, where the - * model considers the results of the tokens with top_p probability mass. So 0.1 - * means only the tokens comprising the top 10% probability mass are considered. - * - * We generally recommend altering this or temperature but not both. - */ - top_p?: number | null; - - /** - * Controls for how a thread will be truncated prior to the run. Use this to - * control the intial context window of the run. - */ - truncation_strategy?: ThreadCreateAndRunStreamParams.TruncationStrategy | null; -} - -export namespace ThreadCreateAndRunStreamParams { - /** - * If no thread is provided, an empty thread will be created. - */ - export interface Thread { - /** - * A list of [messages](https://platform.openai.com/docs/api-reference/messages) to - * start the thread with. - */ - messages?: Array; - - /** - * Set of 16 key-value pairs that can be attached to an object. This can be useful - * for storing additional information about the object in a structured format. Keys - * can be a maximum of 64 characters long and values can be a maxium of 512 - * characters long. - */ - metadata?: unknown | null; - - /** - * A set of resources that are made available to the assistant's tools in this - * thread. The resources are specific to the type of tool. For example, the - * `code_interpreter` tool requires a list of file IDs, while the `file_search` - * tool requires a list of vector store IDs. - */ - tool_resources?: Thread.ToolResources | null; - } - - export namespace Thread { - export interface Message { - /** - * The text contents of the message. - */ - content: string | Array; - - /** - * The role of the entity that is creating the message. Allowed values include: - * - * - `user`: Indicates the message is sent by an actual user and should be used in - * most cases to represent user-generated messages. - * - `assistant`: Indicates the message is generated by the assistant. Use this - * value to insert messages from the assistant into the conversation. - */ - role: 'user' | 'assistant'; - - /** - * A list of files attached to the message, and the tools they should be added to. - */ - attachments?: Array | null; - - /** - * Set of 16 key-value pairs that can be attached to an object. This can be useful - * for storing additional information about the object in a structured format. Keys - * can be a maximum of 64 characters long and values can be a maxium of 512 - * characters long. - */ - metadata?: unknown | null; - } - - export namespace Message { - export interface Attachment { - /** - * The ID of the file to attach to the message. - */ - file_id?: string; - - /** - * The tools to add this file to. - */ - tools?: Array; - } - } - - /** - * A set of resources that are made available to the assistant's tools in this - * thread. The resources are specific to the type of tool. For example, the - * `code_interpreter` tool requires a list of file IDs, while the `file_search` - * tool requires a list of vector store IDs. - */ - export interface ToolResources { - code_interpreter?: ToolResources.CodeInterpreter; - - file_search?: ToolResources.FileSearch; - } - - export namespace ToolResources { - export interface CodeInterpreter { - /** - * A list of [file](https://platform.openai.com/docs/api-reference/files) IDs made - * available to the `code_interpreter` tool. There can be a maximum of 20 files - * associated with the tool. - */ - file_ids?: Array; - } - - export interface FileSearch { - /** - * The - * [vector store](https://platform.openai.com/docs/api-reference/vector-stores/object) - * attached to this thread. There can be a maximum of 1 vector store attached to - * the thread. - */ - vector_store_ids?: Array; - - /** - * A helper to create a - * [vector store](https://platform.openai.com/docs/api-reference/vector-stores/object) - * with file_ids and attach it to this thread. There can be a maximum of 1 vector - * store attached to the thread. - */ - vector_stores?: Array; - } - - export namespace FileSearch { - export interface VectorStore { - /** - * A list of [file](https://platform.openai.com/docs/api-reference/files) IDs to - * add to the vector store. There can be a maximum of 10000 files in a vector - * store. - */ - file_ids?: Array; - - /** - * Set of 16 key-value pairs that can be attached to a vector store. This can be - * useful for storing additional information about the vector store in a structured - * format. Keys can be a maximum of 64 characters long and values can be a maxium - * of 512 characters long. - */ - metadata?: unknown; - } - } - } - } - - /** - * A set of resources that are used by the assistant's tools. The resources are - * specific to the type of tool. For example, the `code_interpreter` tool requires - * a list of file IDs, while the `file_search` tool requires a list of vector store - * IDs. - */ - export interface ToolResources { - code_interpreter?: ToolResources.CodeInterpreter; - - file_search?: ToolResources.FileSearch; - } - - export namespace ToolResources { - export interface CodeInterpreter { - /** - * A list of [file](https://platform.openai.com/docs/api-reference/files) IDs made - * available to the `code_interpreter` tool. There can be a maximum of 20 files - * associated with the tool. - */ - file_ids?: Array; - } - - export interface FileSearch { - /** - * The ID of the - * [vector store](https://platform.openai.com/docs/api-reference/vector-stores/object) - * attached to this assistant. There can be a maximum of 1 vector store attached to - * the assistant. - */ - vector_store_ids?: Array; - } - } - - /** - * Controls for how a thread will be truncated prior to the run. Use this to - * control the intial context window of the run. - */ - export interface TruncationStrategy { - /** - * The truncation strategy to use for the thread. The default is `auto`. If set to - * `last_messages`, the thread will be truncated to the n most recent messages in - * the thread. When set to `auto`, messages in the middle of the thread will be - * dropped to fit the context length of the model, `max_prompt_tokens`. - */ - type: 'auto' | 'last_messages'; - - /** - * The number of most recent messages from the thread when constructing the context - * for the run. - */ - last_messages?: number | null; - } -} +export type ThreadCreateAndRunStreamParams = ThreadCreateAndRunParamsBaseStream; Threads.Runs = Runs; -Threads.RunsPage = RunsPage; Threads.Messages = Messages; -Threads.MessagesPage = MessagesPage; export declare namespace Threads { export { @@ -1571,12 +1250,14 @@ export declare namespace Threads { type RequiredActionFunctionToolCall as RequiredActionFunctionToolCall, type Run as Run, type RunStatus as RunStatus, - RunsPage as RunsPage, + type RunsPage as RunsPage, type RunCreateParams as RunCreateParams, type RunCreateParamsNonStreaming as RunCreateParamsNonStreaming, type RunCreateParamsStreaming as RunCreateParamsStreaming, + type RunRetrieveParams as RunRetrieveParams, type RunUpdateParams as RunUpdateParams, type RunListParams as RunListParams, + type RunCancelParams as RunCancelParams, type RunCreateAndPollParams, type RunCreateAndStreamParams, type RunStreamParams, @@ -1617,9 +1298,11 @@ export declare namespace Threads { type TextContentBlockParam as TextContentBlockParam, type TextDelta as TextDelta, type TextDeltaBlock as TextDeltaBlock, - MessagesPage as MessagesPage, + type MessagesPage as MessagesPage, type MessageCreateParams as MessageCreateParams, + type MessageRetrieveParams as MessageRetrieveParams, type MessageUpdateParams as MessageUpdateParams, type MessageListParams as MessageListParams, + type MessageDeleteParams as MessageDeleteParams, }; } diff --git a/src/resources/beta/vector-stores/file-batches.ts b/src/resources/beta/vector-stores/file-batches.ts index 2c47cb9c2..4cb62feb8 100644 --- a/src/resources/beta/vector-stores/file-batches.ts +++ b/src/resources/beta/vector-stores/file-batches.ts @@ -1,29 +1,31 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import { APIResource } from '../../../resource'; -import { isRequestOptions } from '../../../core'; -import { sleep } from '../../../core'; -import { Uploadable } from '../../../core'; -import { allSettledWithThrow } from '../../../lib/Util'; -import * as Core from '../../../core'; import * as FilesAPI from './files'; import { VectorStoreFilesPage } from './files'; import * as VectorStoresAPI from './vector-stores'; -import { type CursorPageParams } from '../../../pagination'; +import { APIPromise } from '../../../api-promise'; +import { CursorPage, type CursorPageParams, PagePromise } from '../../../pagination'; +import { buildHeaders } from '../../../internal/headers'; +import { RequestOptions } from '../../../internal/request-options'; +import { sleep } from '../../../internal/utils/sleep'; +import { type Uploadable } from '../../../uploads'; +import { allSettledWithThrow } from '../../../lib/Util'; +import { path } from '../../../internal/utils/path'; export class FileBatches extends APIResource { /** * Create a vector store file batch. */ create( - vectorStoreId: string, + vectorStoreID: string, body: FileBatchCreateParams, - options?: Core.RequestOptions, - ): Core.APIPromise { - return this._client.post(`/vector_stores/${vectorStoreId}/file_batches`, { + options?: RequestOptions, + ): APIPromise { + return this._client.post(path`/vector_stores/${vectorStoreID}/file_batches`, { body, ...options, - headers: { 'OpenAI-Beta': 'assistants=v2', ...options?.headers }, + headers: buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), }); } @@ -31,13 +33,14 @@ export class FileBatches extends APIResource { * Retrieves a vector store file batch. */ retrieve( - vectorStoreId: string, - batchId: string, - options?: Core.RequestOptions, - ): Core.APIPromise { - return this._client.get(`/vector_stores/${vectorStoreId}/file_batches/${batchId}`, { + batchID: string, + params: FileBatchRetrieveParams, + options?: RequestOptions, + ): APIPromise { + const { vector_store_id } = params; + return this._client.get(path`/vector_stores/${vector_store_id}/file_batches/${batchID}`, { ...options, - headers: { 'OpenAI-Beta': 'assistants=v2', ...options?.headers }, + headers: buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), }); } @@ -46,13 +49,14 @@ export class FileBatches extends APIResource { * files in this batch as soon as possible. */ cancel( - vectorStoreId: string, - batchId: string, - options?: Core.RequestOptions, - ): Core.APIPromise { - return this._client.post(`/vector_stores/${vectorStoreId}/file_batches/${batchId}/cancel`, { + batchID: string, + params: FileBatchCancelParams, + options?: RequestOptions, + ): APIPromise { + const { vector_store_id } = params; + return this._client.post(path`/vector_stores/${vector_store_id}/file_batches/${batchID}/cancel`, { ...options, - headers: { 'OpenAI-Beta': 'assistants=v2', ...options?.headers }, + headers: buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), }); } @@ -62,7 +66,7 @@ export class FileBatches extends APIResource { async createAndPoll( vectorStoreId: string, body: FileBatchCreateParams, - options?: Core.RequestOptions & { pollIntervalMs?: number }, + options?: RequestOptions & { pollIntervalMs?: number }, ): Promise { const batch = await this.create(vectorStoreId, body); return await this.poll(vectorStoreId, batch.id, options); @@ -72,29 +76,15 @@ export class FileBatches extends APIResource { * Returns a list of vector store files in a batch. */ listFiles( - vectorStoreId: string, - batchId: string, - query?: FileBatchListFilesParams, - options?: Core.RequestOptions, - ): Core.PagePromise; - listFiles( - vectorStoreId: string, - batchId: string, - options?: Core.RequestOptions, - ): Core.PagePromise; - listFiles( - vectorStoreId: string, - batchId: string, - query: FileBatchListFilesParams | Core.RequestOptions = {}, - options?: Core.RequestOptions, - ): Core.PagePromise { - if (isRequestOptions(query)) { - return this.listFiles(vectorStoreId, batchId, {}, query); - } + batchID: string, + params: FileBatchListFilesParams, + options?: RequestOptions, + ): PagePromise { + const { vector_store_id, ...query } = params; return this._client.getAPIList( - `/vector_stores/${vectorStoreId}/file_batches/${batchId}/files`, - VectorStoreFilesPage, - { query, ...options, headers: { 'OpenAI-Beta': 'assistants=v2', ...options?.headers } }, + path`/vector_stores/${vector_store_id}/file_batches/${batchID}/files`, + CursorPage, + { query, ...options, headers: buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]) }, ); } @@ -105,20 +95,27 @@ export class FileBatches extends APIResource { * check batch.file_counts.failed_count to handle this case. */ async poll( - vectorStoreId: string, - batchId: string, - options?: Core.RequestOptions & { pollIntervalMs?: number }, + vectorStoreID: string, + batchID: string, + options?: RequestOptions & { pollIntervalMs?: number }, ): Promise { - const headers: { [key: string]: string } = { ...options?.headers, 'X-Stainless-Poll-Helper': 'true' }; - if (options?.pollIntervalMs) { - headers['X-Stainless-Custom-Poll-Interval'] = options.pollIntervalMs.toString(); - } + const headers = buildHeaders([ + options?.headers, + { + 'X-Stainless-Poll-Helper': 'true', + 'X-Stainless-Custom-Poll-Interval': options?.pollIntervalMs?.toString() ?? undefined, + }, + ]); while (true) { - const { data: batch, response } = await this.retrieve(vectorStoreId, batchId, { - ...options, - headers, - }).withResponse(); + const { data: batch, response } = await this.retrieve( + batchID, + { vector_store_id: vectorStoreID }, + { + ...options, + headers, + }, + ).withResponse(); switch (batch.status) { case 'in_progress': @@ -153,7 +150,7 @@ export class FileBatches extends APIResource { async uploadAndPoll( vectorStoreId: string, { files, fileIds = [] }: { files: Uploadable[]; fileIds?: string[] }, - options?: Core.RequestOptions & { pollIntervalMs?: number; maxConcurrency?: number }, + options?: RequestOptions & { pollIntervalMs?: number; maxConcurrency?: number }, ): Promise { if (files == null || files.length == 0) { throw new Error( @@ -272,23 +269,43 @@ export interface FileBatchCreateParams { chunking_strategy?: VectorStoresAPI.FileChunkingStrategyParam; } +export interface FileBatchRetrieveParams { + /** + * The ID of the vector store that the file batch belongs to. + */ + vector_store_id: string; +} + +export interface FileBatchCancelParams { + /** + * The ID of the vector store that the file batch belongs to. + */ + vector_store_id: string; +} + export interface FileBatchListFilesParams extends CursorPageParams { /** - * A cursor for use in pagination. `before` is an object ID that defines your place - * in the list. For instance, if you make a list request and receive 100 objects, - * starting with obj_foo, your subsequent call can include before=obj_foo in order - * to fetch the previous page of the list. + * Path param: The ID of the vector store that the files belong to. + */ + vector_store_id: string; + + /** + * Query param: A cursor for use in pagination. `before` is an object ID that + * defines your place in the list. For instance, if you make a list request and + * receive 100 objects, starting with obj_foo, your subsequent call can include + * before=obj_foo in order to fetch the previous page of the list. */ before?: string; /** - * Filter by file status. One of `in_progress`, `completed`, `failed`, `cancelled`. + * Query param: Filter by file status. One of `in_progress`, `completed`, `failed`, + * `cancelled`. */ filter?: 'in_progress' | 'completed' | 'failed' | 'cancelled'; /** - * Sort order by the `created_at` timestamp of the objects. `asc` for ascending - * order and `desc` for descending order. + * Query param: Sort order by the `created_at` timestamp of the objects. `asc` for + * ascending order and `desc` for descending order. */ order?: 'asc' | 'desc'; } @@ -297,8 +314,10 @@ export declare namespace FileBatches { export { type VectorStoreFileBatch as VectorStoreFileBatch, type FileBatchCreateParams as FileBatchCreateParams, + type FileBatchRetrieveParams as FileBatchRetrieveParams, + type FileBatchCancelParams as FileBatchCancelParams, type FileBatchListFilesParams as FileBatchListFilesParams, }; } -export { VectorStoreFilesPage }; +export { type VectorStoreFilesPage }; diff --git a/src/resources/beta/vector-stores/files.ts b/src/resources/beta/vector-stores/files.ts index 1fda9a99b..2c499930e 100644 --- a/src/resources/beta/vector-stores/files.ts +++ b/src/resources/beta/vector-stores/files.ts @@ -1,10 +1,14 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import { APIResource } from '../../../resource'; -import { sleep, Uploadable, isRequestOptions } from '../../../core'; -import * as Core from '../../../core'; import * as VectorStoresAPI from './vector-stores'; -import { CursorPage, type CursorPageParams } from '../../../pagination'; +import { APIPromise } from '../../../api-promise'; +import { CursorPage, type CursorPageParams, PagePromise } from '../../../pagination'; +import { buildHeaders } from '../../../internal/headers'; +import { RequestOptions } from '../../../internal/request-options'; +import { sleep } from '../../../internal/utils'; +import { Uploadable } from '../../../uploads'; +import { path } from '../../../internal/utils/path'; export class Files extends APIResource { /** @@ -13,14 +17,14 @@ export class Files extends APIResource { * [vector store](https://platform.openai.com/docs/api-reference/vector-stores/object). */ create( - vectorStoreId: string, + vectorStoreID: string, body: FileCreateParams, - options?: Core.RequestOptions, - ): Core.APIPromise { - return this._client.post(`/vector_stores/${vectorStoreId}/files`, { + options?: RequestOptions, + ): APIPromise { + return this._client.post(path`/vector_stores/${vectorStoreID}/files`, { body, ...options, - headers: { 'OpenAI-Beta': 'assistants=v2', ...options?.headers }, + headers: buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), }); } @@ -28,13 +32,14 @@ export class Files extends APIResource { * Retrieves a vector store file. */ retrieve( - vectorStoreId: string, - fileId: string, - options?: Core.RequestOptions, - ): Core.APIPromise { - return this._client.get(`/vector_stores/${vectorStoreId}/files/${fileId}`, { + fileID: string, + params: FileRetrieveParams, + options?: RequestOptions, + ): APIPromise { + const { vector_store_id } = params; + return this._client.get(path`/vector_stores/${vector_store_id}/files/${fileID}`, { ...options, - headers: { 'OpenAI-Beta': 'assistants=v2', ...options?.headers }, + headers: buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), }); } @@ -42,26 +47,14 @@ export class Files extends APIResource { * Returns a list of vector store files. */ list( - vectorStoreId: string, - query?: FileListParams, - options?: Core.RequestOptions, - ): Core.PagePromise; - list( - vectorStoreId: string, - options?: Core.RequestOptions, - ): Core.PagePromise; - list( - vectorStoreId: string, - query: FileListParams | Core.RequestOptions = {}, - options?: Core.RequestOptions, - ): Core.PagePromise { - if (isRequestOptions(query)) { - return this.list(vectorStoreId, {}, query); - } - return this._client.getAPIList(`/vector_stores/${vectorStoreId}/files`, VectorStoreFilesPage, { + vectorStoreID: string, + query: FileListParams | null | undefined = {}, + options?: RequestOptions, + ): PagePromise { + return this._client.getAPIList(path`/vector_stores/${vectorStoreID}/files`, CursorPage, { query, ...options, - headers: { 'OpenAI-Beta': 'assistants=v2', ...options?.headers }, + headers: buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), }); } @@ -71,14 +64,15 @@ export class Files extends APIResource { * [delete file](https://platform.openai.com/docs/api-reference/files/delete) * endpoint. */ - del( - vectorStoreId: string, - fileId: string, - options?: Core.RequestOptions, - ): Core.APIPromise { - return this._client.delete(`/vector_stores/${vectorStoreId}/files/${fileId}`, { + delete( + fileID: string, + params: FileDeleteParams, + options?: RequestOptions, + ): APIPromise { + const { vector_store_id } = params; + return this._client.delete(path`/vector_stores/${vector_store_id}/files/${fileID}`, { ...options, - headers: { 'OpenAI-Beta': 'assistants=v2', ...options?.headers }, + headers: buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), }); } @@ -88,7 +82,7 @@ export class Files extends APIResource { async createAndPoll( vectorStoreId: string, body: FileCreateParams, - options?: Core.RequestOptions & { pollIntervalMs?: number }, + options?: RequestOptions & { pollIntervalMs?: number }, ): Promise { const file = await this.create(vectorStoreId, body, options); return await this.poll(vectorStoreId, file.id, options); @@ -101,19 +95,26 @@ export class Files extends APIResource { * file.last_error and file.status to handle these cases */ async poll( - vectorStoreId: string, - fileId: string, - options?: Core.RequestOptions & { pollIntervalMs?: number }, + vectorStoreID: string, + fileID: string, + options?: RequestOptions & { pollIntervalMs?: number }, ): Promise { - const headers: { [key: string]: string } = { ...options?.headers, 'X-Stainless-Poll-Helper': 'true' }; - if (options?.pollIntervalMs) { - headers['X-Stainless-Custom-Poll-Interval'] = options.pollIntervalMs.toString(); - } + const headers = buildHeaders([ + options?.headers, + { + 'X-Stainless-Poll-Helper': 'true', + 'X-Stainless-Custom-Poll-Interval': options?.pollIntervalMs?.toString() ?? undefined, + }, + ]); + while (true) { - const fileResponse = await this.retrieve(vectorStoreId, fileId, { - ...options, - headers, - }).withResponse(); + const fileResponse = await this.retrieve( + fileID, + { + vector_store_id: vectorStoreID, + }, + { ...options, headers }, + ).withResponse(); const file = fileResponse.data; @@ -147,11 +148,7 @@ export class Files extends APIResource { * Note the file will be asynchronously processed (you can use the alternative * polling helper method to wait for processing to complete). */ - async upload( - vectorStoreId: string, - file: Uploadable, - options?: Core.RequestOptions, - ): Promise { + async upload(vectorStoreId: string, file: Uploadable, options?: RequestOptions): Promise { const fileInfo = await this._client.files.create({ file: file, purpose: 'assistants' }, options); return this.create(vectorStoreId, { file_id: fileInfo.id }, options); } @@ -162,14 +159,14 @@ export class Files extends APIResource { async uploadAndPoll( vectorStoreId: string, file: Uploadable, - options?: Core.RequestOptions & { pollIntervalMs?: number }, + options?: RequestOptions & { pollIntervalMs?: number }, ): Promise { const fileInfo = await this.upload(vectorStoreId, file, options); return await this.poll(vectorStoreId, fileInfo.id, options); } } -export class VectorStoreFilesPage extends CursorPage {} +export type VectorStoreFilesPage = CursorPage; /** * A list of files attached to a vector store. @@ -264,6 +261,13 @@ export interface FileCreateParams { chunking_strategy?: VectorStoresAPI.FileChunkingStrategyParam; } +export interface FileRetrieveParams { + /** + * The ID of the vector store that the file belongs to. + */ + vector_store_id: string; +} + export interface FileListParams extends CursorPageParams { /** * A cursor for use in pagination. `before` is an object ID that defines your place @@ -285,14 +289,21 @@ export interface FileListParams extends CursorPageParams { order?: 'asc' | 'desc'; } -Files.VectorStoreFilesPage = VectorStoreFilesPage; +export interface FileDeleteParams { + /** + * The ID of the vector store that the file belongs to. + */ + vector_store_id: string; +} export declare namespace Files { export { type VectorStoreFile as VectorStoreFile, type VectorStoreFileDeleted as VectorStoreFileDeleted, - VectorStoreFilesPage as VectorStoreFilesPage, + type VectorStoreFilesPage as VectorStoreFilesPage, type FileCreateParams as FileCreateParams, + type FileRetrieveParams as FileRetrieveParams, type FileListParams as FileListParams, + type FileDeleteParams as FileDeleteParams, }; } diff --git a/src/resources/beta/vector-stores/index.ts b/src/resources/beta/vector-stores/index.ts index 89fc0cde0..d3353db63 100644 --- a/src/resources/beta/vector-stores/index.ts +++ b/src/resources/beta/vector-stores/index.ts @@ -4,18 +4,21 @@ export { FileBatches, type VectorStoreFileBatch, type FileBatchCreateParams, + type FileBatchRetrieveParams, + type FileBatchCancelParams, type FileBatchListFilesParams, } from './file-batches'; export { - VectorStoreFilesPage, Files, type VectorStoreFile, type VectorStoreFileDeleted, type FileCreateParams, + type FileRetrieveParams, type FileListParams, + type FileDeleteParams, + type VectorStoreFilesPage, } from './files'; export { - VectorStoresPage, VectorStores, type AutoFileChunkingStrategyParam, type FileChunkingStrategy, @@ -23,10 +26,11 @@ export { type OtherFileChunkingStrategyObject, type StaticFileChunkingStrategy, type StaticFileChunkingStrategyObject, - type StaticFileChunkingStrategyParam, + type StaticFileChunkingStrategyObjectParam, type VectorStore, type VectorStoreDeleted, type VectorStoreCreateParams, type VectorStoreUpdateParams, type VectorStoreListParams, + type VectorStoresPage, } from './vector-stores'; diff --git a/src/resources/beta/vector-stores/vector-stores.ts b/src/resources/beta/vector-stores/vector-stores.ts index 35ad8c369..94f32905e 100644 --- a/src/resources/beta/vector-stores/vector-stores.ts +++ b/src/resources/beta/vector-stores/vector-stores.ts @@ -1,25 +1,32 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import { APIResource } from '../../../resource'; -import { isRequestOptions } from '../../../core'; -import * as Core from '../../../core'; +import * as Shared from '../../shared'; import * as FileBatchesAPI from './file-batches'; import { + FileBatchCancelParams, FileBatchCreateParams, FileBatchListFilesParams, + FileBatchRetrieveParams, FileBatches, VectorStoreFileBatch, } from './file-batches'; import * as FilesAPI from './files'; import { FileCreateParams, + FileDeleteParams, FileListParams, + FileRetrieveParams, Files, VectorStoreFile, VectorStoreFileDeleted, VectorStoreFilesPage, } from './files'; -import { CursorPage, type CursorPageParams } from '../../../pagination'; +import { APIPromise } from '../../../api-promise'; +import { CursorPage, type CursorPageParams, PagePromise } from '../../../pagination'; +import { buildHeaders } from '../../../internal/headers'; +import { RequestOptions } from '../../../internal/request-options'; +import { path } from '../../../internal/utils/path'; export class VectorStores extends APIResource { files: FilesAPI.Files = new FilesAPI.Files(this._client); @@ -28,21 +35,21 @@ export class VectorStores extends APIResource { /** * Create a vector store. */ - create(body: VectorStoreCreateParams, options?: Core.RequestOptions): Core.APIPromise { + create(body: VectorStoreCreateParams, options?: RequestOptions): APIPromise { return this._client.post('/vector_stores', { body, ...options, - headers: { 'OpenAI-Beta': 'assistants=v2', ...options?.headers }, + headers: buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), }); } /** * Retrieves a vector store. */ - retrieve(vectorStoreId: string, options?: Core.RequestOptions): Core.APIPromise { - return this._client.get(`/vector_stores/${vectorStoreId}`, { + retrieve(vectorStoreID: string, options?: RequestOptions): APIPromise { + return this._client.get(path`/vector_stores/${vectorStoreID}`, { ...options, - headers: { 'OpenAI-Beta': 'assistants=v2', ...options?.headers }, + headers: buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), }); } @@ -50,14 +57,14 @@ export class VectorStores extends APIResource { * Modifies a vector store. */ update( - vectorStoreId: string, + vectorStoreID: string, body: VectorStoreUpdateParams, - options?: Core.RequestOptions, - ): Core.APIPromise { - return this._client.post(`/vector_stores/${vectorStoreId}`, { + options?: RequestOptions, + ): APIPromise { + return this._client.post(path`/vector_stores/${vectorStoreID}`, { body, ...options, - headers: { 'OpenAI-Beta': 'assistants=v2', ...options?.headers }, + headers: buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), }); } @@ -65,36 +72,28 @@ export class VectorStores extends APIResource { * Returns a list of vector stores. */ list( - query?: VectorStoreListParams, - options?: Core.RequestOptions, - ): Core.PagePromise; - list(options?: Core.RequestOptions): Core.PagePromise; - list( - query: VectorStoreListParams | Core.RequestOptions = {}, - options?: Core.RequestOptions, - ): Core.PagePromise { - if (isRequestOptions(query)) { - return this.list({}, query); - } - return this._client.getAPIList('/vector_stores', VectorStoresPage, { + query: VectorStoreListParams | null | undefined = {}, + options?: RequestOptions, + ): PagePromise { + return this._client.getAPIList('/vector_stores', CursorPage, { query, ...options, - headers: { 'OpenAI-Beta': 'assistants=v2', ...options?.headers }, + headers: buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), }); } /** * Delete a vector store. */ - del(vectorStoreId: string, options?: Core.RequestOptions): Core.APIPromise { - return this._client.delete(`/vector_stores/${vectorStoreId}`, { + delete(vectorStoreID: string, options?: RequestOptions): APIPromise { + return this._client.delete(path`/vector_stores/${vectorStoreID}`, { ...options, - headers: { 'OpenAI-Beta': 'assistants=v2', ...options?.headers }, + headers: buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), }); } } -export class VectorStoresPage extends CursorPage {} +export type VectorStoresPage = CursorPage; /** * The default strategy. This strategy currently uses a `max_chunk_size_tokens` of @@ -116,7 +115,7 @@ export type FileChunkingStrategy = StaticFileChunkingStrategyObject | OtherFileC * The chunking strategy used to chunk the file(s). If not set, will use the `auto` * strategy. Only applicable if `file_ids` is non-empty. */ -export type FileChunkingStrategyParam = AutoFileChunkingStrategyParam | StaticFileChunkingStrategyParam; +export type FileChunkingStrategyParam = AutoFileChunkingStrategyParam | StaticFileChunkingStrategyObjectParam; /** * This is returned when the chunking strategy is unknown. Typically, this is @@ -154,7 +153,7 @@ export interface StaticFileChunkingStrategyObject { type: 'static'; } -export interface StaticFileChunkingStrategyParam { +export interface StaticFileChunkingStrategyObjectParam { static: StaticFileChunkingStrategy; /** @@ -187,11 +186,13 @@ export interface VectorStore { /** * Set of 16 key-value pairs that can be attached to an object. This can be useful - * for storing additional information about the object in a structured format. Keys - * can be a maximum of 64 characters long and values can be a maxium of 512 - * characters long. + * for storing additional information about the object in a structured format, and + * querying for objects via API or the dashboard. + * + * Keys are strings with a maximum length of 64 characters. Values are strings with + * a maximum length of 512 characters. */ - metadata: unknown | null; + metadata: Shared.Metadata | null; /** * The name of the vector store. @@ -300,11 +301,13 @@ export interface VectorStoreCreateParams { /** * Set of 16 key-value pairs that can be attached to an object. This can be useful - * for storing additional information about the object in a structured format. Keys - * can be a maximum of 64 characters long and values can be a maxium of 512 - * characters long. + * for storing additional information about the object in a structured format, and + * querying for objects via API or the dashboard. + * + * Keys are strings with a maximum length of 64 characters. Values are strings with + * a maximum length of 512 characters. */ - metadata?: unknown | null; + metadata?: Shared.Metadata | null; /** * The name of the vector store. @@ -338,11 +341,13 @@ export interface VectorStoreUpdateParams { /** * Set of 16 key-value pairs that can be attached to an object. This can be useful - * for storing additional information about the object in a structured format. Keys - * can be a maximum of 64 characters long and values can be a maxium of 512 - * characters long. + * for storing additional information about the object in a structured format, and + * querying for objects via API or the dashboard. + * + * Keys are strings with a maximum length of 64 characters. Values are strings with + * a maximum length of 512 characters. */ - metadata?: unknown | null; + metadata?: Shared.Metadata | null; /** * The name of the vector store. @@ -384,9 +389,7 @@ export interface VectorStoreListParams extends CursorPageParams { order?: 'asc' | 'desc'; } -VectorStores.VectorStoresPage = VectorStoresPage; VectorStores.Files = Files; -VectorStores.VectorStoreFilesPage = VectorStoreFilesPage; VectorStores.FileBatches = FileBatches; export declare namespace VectorStores { @@ -397,10 +400,10 @@ export declare namespace VectorStores { type OtherFileChunkingStrategyObject as OtherFileChunkingStrategyObject, type StaticFileChunkingStrategy as StaticFileChunkingStrategy, type StaticFileChunkingStrategyObject as StaticFileChunkingStrategyObject, - type StaticFileChunkingStrategyParam as StaticFileChunkingStrategyParam, + type StaticFileChunkingStrategyObjectParam as StaticFileChunkingStrategyObjectParam, type VectorStore as VectorStore, type VectorStoreDeleted as VectorStoreDeleted, - VectorStoresPage as VectorStoresPage, + type VectorStoresPage as VectorStoresPage, type VectorStoreCreateParams as VectorStoreCreateParams, type VectorStoreUpdateParams as VectorStoreUpdateParams, type VectorStoreListParams as VectorStoreListParams, @@ -410,15 +413,19 @@ export declare namespace VectorStores { Files as Files, type VectorStoreFile as VectorStoreFile, type VectorStoreFileDeleted as VectorStoreFileDeleted, - VectorStoreFilesPage as VectorStoreFilesPage, + type VectorStoreFilesPage as VectorStoreFilesPage, type FileCreateParams as FileCreateParams, + type FileRetrieveParams as FileRetrieveParams, type FileListParams as FileListParams, + type FileDeleteParams as FileDeleteParams, }; export { FileBatches as FileBatches, type VectorStoreFileBatch as VectorStoreFileBatch, type FileBatchCreateParams as FileBatchCreateParams, + type FileBatchRetrieveParams as FileBatchRetrieveParams, + type FileBatchCancelParams as FileBatchCancelParams, type FileBatchListFilesParams as FileBatchListFilesParams, }; } diff --git a/src/resources/chat/chat.ts b/src/resources/chat/chat.ts index 2230b19bd..40358c331 100644 --- a/src/resources/chat/chat.ts +++ b/src/resources/chat/chat.ts @@ -1,7 +1,7 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import { APIResource } from '../../resource'; -import * as CompletionsAPI from './completions'; +import * as CompletionsAPI from './completions/completions'; import { ChatCompletion, ChatCompletionAssistantMessageParam, @@ -16,9 +16,11 @@ import { ChatCompletionCreateParams, ChatCompletionCreateParamsNonStreaming, ChatCompletionCreateParamsStreaming, + ChatCompletionDeleted, ChatCompletionDeveloperMessageParam, ChatCompletionFunctionCallOption, ChatCompletionFunctionMessageParam, + ChatCompletionListParams, ChatCompletionMessage, ChatCompletionMessageParam, ChatCompletionMessageToolCall, @@ -27,31 +29,34 @@ import { ChatCompletionPredictionContent, ChatCompletionReasoningEffort, ChatCompletionRole, + ChatCompletionStoreMessage, ChatCompletionStreamOptions, ChatCompletionSystemMessageParam, ChatCompletionTokenLogprob, ChatCompletionTool, ChatCompletionToolChoiceOption, ChatCompletionToolMessageParam, + ChatCompletionUpdateParams, ChatCompletionUserMessageParam, - CompletionCreateParams, - CompletionCreateParamsNonStreaming, - CompletionCreateParamsStreaming, + ChatCompletionsPage, Completions, - CreateChatCompletionRequestMessage, -} from './completions'; +} from './completions/completions'; export class Chat extends APIResource { completions: CompletionsAPI.Completions = new CompletionsAPI.Completions(this._client); } export type ChatModel = + | 'o3-mini' + | 'o3-mini-2025-01-31' | 'o1' | 'o1-2024-12-17' | 'o1-preview' | 'o1-preview-2024-09-12' | 'o1-mini' | 'o1-mini-2024-09-12' + | 'gpt-4.5-preview' + | 'gpt-4.5-preview-2025-02-27' | 'gpt-4o' | 'gpt-4o-2024-11-20' | 'gpt-4o-2024-08-06' @@ -101,6 +106,7 @@ export declare namespace Chat { type ChatCompletionContentPartInputAudio as ChatCompletionContentPartInputAudio, type ChatCompletionContentPartRefusal as ChatCompletionContentPartRefusal, type ChatCompletionContentPartText as ChatCompletionContentPartText, + type ChatCompletionDeleted as ChatCompletionDeleted, type ChatCompletionDeveloperMessageParam as ChatCompletionDeveloperMessageParam, type ChatCompletionFunctionCallOption as ChatCompletionFunctionCallOption, type ChatCompletionFunctionMessageParam as ChatCompletionFunctionMessageParam, @@ -112,6 +118,7 @@ export declare namespace Chat { type ChatCompletionPredictionContent as ChatCompletionPredictionContent, type ChatCompletionReasoningEffort as ChatCompletionReasoningEffort, type ChatCompletionRole as ChatCompletionRole, + type ChatCompletionStoreMessage as ChatCompletionStoreMessage, type ChatCompletionStreamOptions as ChatCompletionStreamOptions, type ChatCompletionSystemMessageParam as ChatCompletionSystemMessageParam, type ChatCompletionTokenLogprob as ChatCompletionTokenLogprob, @@ -119,12 +126,11 @@ export declare namespace Chat { type ChatCompletionToolChoiceOption as ChatCompletionToolChoiceOption, type ChatCompletionToolMessageParam as ChatCompletionToolMessageParam, type ChatCompletionUserMessageParam as ChatCompletionUserMessageParam, - type CreateChatCompletionRequestMessage as CreateChatCompletionRequestMessage, + type ChatCompletionsPage as ChatCompletionsPage, type ChatCompletionCreateParams as ChatCompletionCreateParams, - type CompletionCreateParams as CompletionCreateParams, type ChatCompletionCreateParamsNonStreaming as ChatCompletionCreateParamsNonStreaming, - type CompletionCreateParamsNonStreaming as CompletionCreateParamsNonStreaming, type ChatCompletionCreateParamsStreaming as ChatCompletionCreateParamsStreaming, - type CompletionCreateParamsStreaming as CompletionCreateParamsStreaming, + type ChatCompletionUpdateParams as ChatCompletionUpdateParams, + type ChatCompletionListParams as ChatCompletionListParams, }; } diff --git a/src/resources/chat/completions.ts b/src/resources/chat/completions.ts index 31f5814cb..55b151e8b 100644 --- a/src/resources/chat/completions.ts +++ b/src/resources/chat/completions.ts @@ -1,1314 +1 @@ -// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -import { APIResource } from '../../resource'; -import { APIPromise } from '../../core'; -import * as Core from '../../core'; -import * as ChatCompletionsAPI from './completions'; -import * as CompletionsAPI from '../completions'; -import * as Shared from '../shared'; -import * as ChatAPI from './chat'; -import { Stream } from '../../streaming'; - -export class Completions extends APIResource { - /** - * Creates a model response for the given chat conversation. Learn more in the - * [text generation](https://platform.openai.com/docs/guides/text-generation), - * [vision](https://platform.openai.com/docs/guides/vision), and - * [audio](https://platform.openai.com/docs/guides/audio) guides. - * - * Parameter support can differ depending on the model used to generate the - * response, particularly for newer reasoning models. Parameters that are only - * supported for reasoning models are noted below. For the current state of - * unsupported parameters in reasoning models, - * [refer to the reasoning guide](https://platform.openai.com/docs/guides/reasoning). - */ - create( - body: ChatCompletionCreateParamsNonStreaming, - options?: Core.RequestOptions, - ): APIPromise; - create( - body: ChatCompletionCreateParamsStreaming, - options?: Core.RequestOptions, - ): APIPromise>; - create( - body: ChatCompletionCreateParamsBase, - options?: Core.RequestOptions, - ): APIPromise | ChatCompletion>; - create( - body: ChatCompletionCreateParams, - options?: Core.RequestOptions, - ): APIPromise | APIPromise> { - return this._client.post('/chat/completions', { body, ...options, stream: body.stream ?? false }) as - | APIPromise - | APIPromise>; - } -} - -/** - * Represents a chat completion response returned by model, based on the provided - * input. - */ -export interface ChatCompletion { - /** - * A unique identifier for the chat completion. - */ - id: string; - - /** - * A list of chat completion choices. Can be more than one if `n` is greater - * than 1. - */ - choices: Array; - - /** - * The Unix timestamp (in seconds) of when the chat completion was created. - */ - created: number; - - /** - * The model used for the chat completion. - */ - model: string; - - /** - * The object type, which is always `chat.completion`. - */ - object: 'chat.completion'; - - /** - * The service tier used for processing the request. This field is only included if - * the `service_tier` parameter is specified in the request. - */ - service_tier?: 'scale' | 'default' | null; - - /** - * This fingerprint represents the backend configuration that the model runs with. - * - * Can be used in conjunction with the `seed` request parameter to understand when - * backend changes have been made that might impact determinism. - */ - system_fingerprint?: string; - - /** - * Usage statistics for the completion request. - */ - usage?: CompletionsAPI.CompletionUsage; -} - -export namespace ChatCompletion { - export interface Choice { - /** - * The reason the model stopped generating tokens. This will be `stop` if the model - * hit a natural stop point or a provided stop sequence, `length` if the maximum - * number of tokens specified in the request was reached, `content_filter` if - * content was omitted due to a flag from our content filters, `tool_calls` if the - * model called a tool, or `function_call` (deprecated) if the model called a - * function. - */ - finish_reason: 'stop' | 'length' | 'tool_calls' | 'content_filter' | 'function_call'; - - /** - * The index of the choice in the list of choices. - */ - index: number; - - /** - * Log probability information for the choice. - */ - logprobs: Choice.Logprobs | null; - - /** - * A chat completion message generated by the model. - */ - message: ChatCompletionsAPI.ChatCompletionMessage; - } - - export namespace Choice { - /** - * Log probability information for the choice. - */ - export interface Logprobs { - /** - * A list of message content tokens with log probability information. - */ - content: Array | null; - - /** - * A list of message refusal tokens with log probability information. - */ - refusal: Array | null; - } - } -} - -/** - * Messages sent by the model in response to user messages. - */ -export interface ChatCompletionAssistantMessageParam { - /** - * The role of the messages author, in this case `assistant`. - */ - role: 'assistant'; - - /** - * Data about a previous audio response from the model. - * [Learn more](https://platform.openai.com/docs/guides/audio). - */ - audio?: ChatCompletionAssistantMessageParam.Audio | null; - - /** - * The contents of the assistant message. Required unless `tool_calls` or - * `function_call` is specified. - */ - content?: string | Array | null; - - /** - * @deprecated: Deprecated and replaced by `tool_calls`. The name and arguments of - * a function that should be called, as generated by the model. - */ - function_call?: ChatCompletionAssistantMessageParam.FunctionCall | null; - - /** - * An optional name for the participant. Provides the model information to - * differentiate between participants of the same role. - */ - name?: string; - - /** - * The refusal message by the assistant. - */ - refusal?: string | null; - - /** - * The tool calls generated by the model, such as function calls. - */ - tool_calls?: Array; -} - -export namespace ChatCompletionAssistantMessageParam { - /** - * Data about a previous audio response from the model. - * [Learn more](https://platform.openai.com/docs/guides/audio). - */ - export interface Audio { - /** - * Unique identifier for a previous audio response from the model. - */ - id: string; - } - - /** - * @deprecated: Deprecated and replaced by `tool_calls`. The name and arguments of - * a function that should be called, as generated by the model. - */ - export interface FunctionCall { - /** - * The arguments to call the function with, as generated by the model in JSON - * format. Note that the model does not always generate valid JSON, and may - * hallucinate parameters not defined by your function schema. Validate the - * arguments in your code before calling your function. - */ - arguments: string; - - /** - * The name of the function to call. - */ - name: string; - } -} - -/** - * If the audio output modality is requested, this object contains data about the - * audio response from the model. - * [Learn more](https://platform.openai.com/docs/guides/audio). - */ -export interface ChatCompletionAudio { - /** - * Unique identifier for this audio response. - */ - id: string; - - /** - * Base64 encoded audio bytes generated by the model, in the format specified in - * the request. - */ - data: string; - - /** - * The Unix timestamp (in seconds) for when this audio response will no longer be - * accessible on the server for use in multi-turn conversations. - */ - expires_at: number; - - /** - * Transcript of the audio generated by the model. - */ - transcript: string; -} - -/** - * Parameters for audio output. Required when audio output is requested with - * `modalities: ["audio"]`. - * [Learn more](https://platform.openai.com/docs/guides/audio). - */ -export interface ChatCompletionAudioParam { - /** - * Specifies the output audio format. Must be one of `wav`, `mp3`, `flac`, `opus`, - * or `pcm16`. - */ - format: 'wav' | 'mp3' | 'flac' | 'opus' | 'pcm16'; - - /** - * The voice the model uses to respond. Supported voices are `ash`, `ballad`, - * `coral`, `sage`, and `verse` (also supported but not recommended are `alloy`, - * `echo`, and `shimmer`; these voices are less expressive). - */ - voice: 'alloy' | 'ash' | 'ballad' | 'coral' | 'echo' | 'sage' | 'shimmer' | 'verse'; -} - -/** - * Represents a streamed chunk of a chat completion response returned by model, - * based on the provided input. - */ -export interface ChatCompletionChunk { - /** - * A unique identifier for the chat completion. Each chunk has the same ID. - */ - id: string; - - /** - * A list of chat completion choices. Can contain more than one elements if `n` is - * greater than 1. Can also be empty for the last chunk if you set - * `stream_options: {"include_usage": true}`. - */ - choices: Array; - - /** - * The Unix timestamp (in seconds) of when the chat completion was created. Each - * chunk has the same timestamp. - */ - created: number; - - /** - * The model to generate the completion. - */ - model: string; - - /** - * The object type, which is always `chat.completion.chunk`. - */ - object: 'chat.completion.chunk'; - - /** - * The service tier used for processing the request. This field is only included if - * the `service_tier` parameter is specified in the request. - */ - service_tier?: 'scale' | 'default' | null; - - /** - * This fingerprint represents the backend configuration that the model runs with. - * Can be used in conjunction with the `seed` request parameter to understand when - * backend changes have been made that might impact determinism. - */ - system_fingerprint?: string; - - /** - * An optional field that will only be present when you set - * `stream_options: {"include_usage": true}` in your request. When present, it - * contains a null value except for the last chunk which contains the token usage - * statistics for the entire request. - */ - usage?: CompletionsAPI.CompletionUsage | null; -} - -export namespace ChatCompletionChunk { - export interface Choice { - /** - * A chat completion delta generated by streamed model responses. - */ - delta: Choice.Delta; - - /** - * The reason the model stopped generating tokens. This will be `stop` if the model - * hit a natural stop point or a provided stop sequence, `length` if the maximum - * number of tokens specified in the request was reached, `content_filter` if - * content was omitted due to a flag from our content filters, `tool_calls` if the - * model called a tool, or `function_call` (deprecated) if the model called a - * function. - */ - finish_reason: 'stop' | 'length' | 'tool_calls' | 'content_filter' | 'function_call' | null; - - /** - * The index of the choice in the list of choices. - */ - index: number; - - /** - * Log probability information for the choice. - */ - logprobs?: Choice.Logprobs | null; - } - - export namespace Choice { - /** - * A chat completion delta generated by streamed model responses. - */ - export interface Delta { - /** - * The contents of the chunk message. - */ - content?: string | null; - - /** - * @deprecated: Deprecated and replaced by `tool_calls`. The name and arguments of - * a function that should be called, as generated by the model. - */ - function_call?: Delta.FunctionCall; - - /** - * The refusal message generated by the model. - */ - refusal?: string | null; - - /** - * The role of the author of this message. - */ - role?: 'system' | 'user' | 'assistant' | 'tool'; - - tool_calls?: Array; - } - - export namespace Delta { - /** - * @deprecated: Deprecated and replaced by `tool_calls`. The name and arguments of - * a function that should be called, as generated by the model. - */ - export interface FunctionCall { - /** - * The arguments to call the function with, as generated by the model in JSON - * format. Note that the model does not always generate valid JSON, and may - * hallucinate parameters not defined by your function schema. Validate the - * arguments in your code before calling your function. - */ - arguments?: string; - - /** - * The name of the function to call. - */ - name?: string; - } - - export interface ToolCall { - index: number; - - /** - * The ID of the tool call. - */ - id?: string; - - function?: ToolCall.Function; - - /** - * The type of the tool. Currently, only `function` is supported. - */ - type?: 'function'; - } - - export namespace ToolCall { - export interface Function { - /** - * The arguments to call the function with, as generated by the model in JSON - * format. Note that the model does not always generate valid JSON, and may - * hallucinate parameters not defined by your function schema. Validate the - * arguments in your code before calling your function. - */ - arguments?: string; - - /** - * The name of the function to call. - */ - name?: string; - } - } - } - - /** - * Log probability information for the choice. - */ - export interface Logprobs { - /** - * A list of message content tokens with log probability information. - */ - content: Array | null; - - /** - * A list of message refusal tokens with log probability information. - */ - refusal: Array | null; - } - } -} - -/** - * Learn about - * [text inputs](https://platform.openai.com/docs/guides/text-generation). - */ -export type ChatCompletionContentPart = - | ChatCompletionContentPartText - | ChatCompletionContentPartImage - | ChatCompletionContentPartInputAudio; - -/** - * Learn about [image inputs](https://platform.openai.com/docs/guides/vision). - */ -export interface ChatCompletionContentPartImage { - image_url: ChatCompletionContentPartImage.ImageURL; - - /** - * The type of the content part. - */ - type: 'image_url'; -} - -export namespace ChatCompletionContentPartImage { - export interface ImageURL { - /** - * Either a URL of the image or the base64 encoded image data. - */ - url: string; - - /** - * Specifies the detail level of the image. Learn more in the - * [Vision guide](https://platform.openai.com/docs/guides/vision#low-or-high-fidelity-image-understanding). - */ - detail?: 'auto' | 'low' | 'high'; - } -} - -/** - * Learn about [audio inputs](https://platform.openai.com/docs/guides/audio). - */ -export interface ChatCompletionContentPartInputAudio { - input_audio: ChatCompletionContentPartInputAudio.InputAudio; - - /** - * The type of the content part. Always `input_audio`. - */ - type: 'input_audio'; -} - -export namespace ChatCompletionContentPartInputAudio { - export interface InputAudio { - /** - * Base64 encoded audio data. - */ - data: string; - - /** - * The format of the encoded audio data. Currently supports "wav" and "mp3". - */ - format: 'wav' | 'mp3'; - } -} - -export interface ChatCompletionContentPartRefusal { - /** - * The refusal message generated by the model. - */ - refusal: string; - - /** - * The type of the content part. - */ - type: 'refusal'; -} - -/** - * Learn about - * [text inputs](https://platform.openai.com/docs/guides/text-generation). - */ -export interface ChatCompletionContentPartText { - /** - * The text content. - */ - text: string; - - /** - * The type of the content part. - */ - type: 'text'; -} - -/** - * Developer-provided instructions that the model should follow, regardless of - * messages sent by the user. With o1 models and newer, `developer` messages - * replace the previous `system` messages. - */ -export interface ChatCompletionDeveloperMessageParam { - /** - * The contents of the developer message. - */ - content: string | Array; - - /** - * The role of the messages author, in this case `developer`. - */ - role: 'developer'; - - /** - * An optional name for the participant. Provides the model information to - * differentiate between participants of the same role. - */ - name?: string; -} - -/** - * Specifying a particular function via `{"name": "my_function"}` forces the model - * to call that function. - */ -export interface ChatCompletionFunctionCallOption { - /** - * The name of the function to call. - */ - name: string; -} - -/** - * @deprecated - */ -export interface ChatCompletionFunctionMessageParam { - /** - * The contents of the function message. - */ - content: string | null; - - /** - * The name of the function to call. - */ - name: string; - - /** - * The role of the messages author, in this case `function`. - */ - role: 'function'; -} - -/** - * A chat completion message generated by the model. - */ -export interface ChatCompletionMessage { - /** - * The contents of the message. - */ - content: string | null; - - /** - * The refusal message generated by the model. - */ - refusal: string | null; - - /** - * The role of the author of this message. - */ - role: 'assistant'; - - /** - * If the audio output modality is requested, this object contains data about the - * audio response from the model. - * [Learn more](https://platform.openai.com/docs/guides/audio). - */ - audio?: ChatCompletionAudio | null; - - /** - * @deprecated: Deprecated and replaced by `tool_calls`. The name and arguments of - * a function that should be called, as generated by the model. - */ - function_call?: ChatCompletionMessage.FunctionCall | null; - - /** - * The tool calls generated by the model, such as function calls. - */ - tool_calls?: Array; -} - -export namespace ChatCompletionMessage { - /** - * @deprecated: Deprecated and replaced by `tool_calls`. The name and arguments of - * a function that should be called, as generated by the model. - */ - export interface FunctionCall { - /** - * The arguments to call the function with, as generated by the model in JSON - * format. Note that the model does not always generate valid JSON, and may - * hallucinate parameters not defined by your function schema. Validate the - * arguments in your code before calling your function. - */ - arguments: string; - - /** - * The name of the function to call. - */ - name: string; - } -} - -/** - * Developer-provided instructions that the model should follow, regardless of - * messages sent by the user. With o1 models and newer, `developer` messages - * replace the previous `system` messages. - */ -export type ChatCompletionMessageParam = - | ChatCompletionDeveloperMessageParam - | ChatCompletionSystemMessageParam - | ChatCompletionUserMessageParam - | ChatCompletionAssistantMessageParam - | ChatCompletionToolMessageParam - | ChatCompletionFunctionMessageParam; - -export interface ChatCompletionMessageToolCall { - /** - * The ID of the tool call. - */ - id: string; - - /** - * The function that the model called. - */ - function: ChatCompletionMessageToolCall.Function; - - /** - * The type of the tool. Currently, only `function` is supported. - */ - type: 'function'; -} - -export namespace ChatCompletionMessageToolCall { - /** - * The function that the model called. - */ - export interface Function { - /** - * The arguments to call the function with, as generated by the model in JSON - * format. Note that the model does not always generate valid JSON, and may - * hallucinate parameters not defined by your function schema. Validate the - * arguments in your code before calling your function. - */ - arguments: string; - - /** - * The name of the function to call. - */ - name: string; - } -} - -export type ChatCompletionModality = 'text' | 'audio'; - -/** - * Specifies a tool the model should use. Use to force the model to call a specific - * function. - */ -export interface ChatCompletionNamedToolChoice { - function: ChatCompletionNamedToolChoice.Function; - - /** - * The type of the tool. Currently, only `function` is supported. - */ - type: 'function'; -} - -export namespace ChatCompletionNamedToolChoice { - export interface Function { - /** - * The name of the function to call. - */ - name: string; - } -} - -/** - * Static predicted output content, such as the content of a text file that is - * being regenerated. - */ -export interface ChatCompletionPredictionContent { - /** - * The content that should be matched when generating a model response. If - * generated tokens would match this content, the entire model response can be - * returned much more quickly. - */ - content: string | Array; - - /** - * The type of the predicted content you want to provide. This type is currently - * always `content`. - */ - type: 'content'; -} - -/** - * **o1 models only** - * - * Constrains effort on reasoning for - * [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - * supported values are `low`, `medium`, and `high`. Reducing reasoning effort can - * result in faster responses and fewer tokens used on reasoning in a response. - */ -export type ChatCompletionReasoningEffort = 'low' | 'medium' | 'high'; - -/** - * The role of the author of a message - */ -export type ChatCompletionRole = 'system' | 'user' | 'assistant' | 'tool' | 'function'; - -/** - * Options for streaming response. Only set this when you set `stream: true`. - */ -export interface ChatCompletionStreamOptions { - /** - * If set, an additional chunk will be streamed before the `data: [DONE]` message. - * The `usage` field on this chunk shows the token usage statistics for the entire - * request, and the `choices` field will always be an empty array. All other chunks - * will also include a `usage` field, but with a null value. - */ - include_usage?: boolean; -} - -/** - * Developer-provided instructions that the model should follow, regardless of - * messages sent by the user. With o1 models and newer, use `developer` messages - * for this purpose instead. - */ -export interface ChatCompletionSystemMessageParam { - /** - * The contents of the system message. - */ - content: string | Array; - - /** - * The role of the messages author, in this case `system`. - */ - role: 'system'; - - /** - * An optional name for the participant. Provides the model information to - * differentiate between participants of the same role. - */ - name?: string; -} - -export interface ChatCompletionTokenLogprob { - /** - * The token. - */ - token: string; - - /** - * A list of integers representing the UTF-8 bytes representation of the token. - * Useful in instances where characters are represented by multiple tokens and - * their byte representations must be combined to generate the correct text - * representation. Can be `null` if there is no bytes representation for the token. - */ - bytes: Array | null; - - /** - * The log probability of this token, if it is within the top 20 most likely - * tokens. Otherwise, the value `-9999.0` is used to signify that the token is very - * unlikely. - */ - logprob: number; - - /** - * List of the most likely tokens and their log probability, at this token - * position. In rare cases, there may be fewer than the number of requested - * `top_logprobs` returned. - */ - top_logprobs: Array; -} - -export namespace ChatCompletionTokenLogprob { - export interface TopLogprob { - /** - * The token. - */ - token: string; - - /** - * A list of integers representing the UTF-8 bytes representation of the token. - * Useful in instances where characters are represented by multiple tokens and - * their byte representations must be combined to generate the correct text - * representation. Can be `null` if there is no bytes representation for the token. - */ - bytes: Array | null; - - /** - * The log probability of this token, if it is within the top 20 most likely - * tokens. Otherwise, the value `-9999.0` is used to signify that the token is very - * unlikely. - */ - logprob: number; - } -} - -export interface ChatCompletionTool { - function: Shared.FunctionDefinition; - - /** - * The type of the tool. Currently, only `function` is supported. - */ - type: 'function'; -} - -/** - * Controls which (if any) tool is called by the model. `none` means the model will - * not call any tool and instead generates a message. `auto` means the model can - * pick between generating a message or calling one or more tools. `required` means - * the model must call one or more tools. Specifying a particular tool via - * `{"type": "function", "function": {"name": "my_function"}}` forces the model to - * call that tool. - * - * `none` is the default when no tools are present. `auto` is the default if tools - * are present. - */ -export type ChatCompletionToolChoiceOption = 'none' | 'auto' | 'required' | ChatCompletionNamedToolChoice; - -export interface ChatCompletionToolMessageParam { - /** - * The contents of the tool message. - */ - content: string | Array; - - /** - * The role of the messages author, in this case `tool`. - */ - role: 'tool'; - - /** - * Tool call that this message is responding to. - */ - tool_call_id: string; -} - -/** - * Messages sent by an end user, containing prompts or additional context - * information. - */ -export interface ChatCompletionUserMessageParam { - /** - * The contents of the user message. - */ - content: string | Array; - - /** - * The role of the messages author, in this case `user`. - */ - role: 'user'; - - /** - * An optional name for the participant. Provides the model information to - * differentiate between participants of the same role. - */ - name?: string; -} - -/** - * @deprecated ChatCompletionMessageParam should be used instead - */ -export type CreateChatCompletionRequestMessage = ChatCompletionMessageParam; - -export type ChatCompletionCreateParams = - | ChatCompletionCreateParamsNonStreaming - | ChatCompletionCreateParamsStreaming; - -export interface ChatCompletionCreateParamsBase { - /** - * A list of messages comprising the conversation so far. Depending on the - * [model](https://platform.openai.com/docs/models) you use, different message - * types (modalities) are supported, like - * [text](https://platform.openai.com/docs/guides/text-generation), - * [images](https://platform.openai.com/docs/guides/vision), and - * [audio](https://platform.openai.com/docs/guides/audio). - */ - messages: Array; - - /** - * ID of the model to use. See the - * [model endpoint compatibility](https://platform.openai.com/docs/models#model-endpoint-compatibility) - * table for details on which models work with the Chat API. - */ - model: (string & {}) | ChatAPI.ChatModel; - - /** - * Parameters for audio output. Required when audio output is requested with - * `modalities: ["audio"]`. - * [Learn more](https://platform.openai.com/docs/guides/audio). - */ - audio?: ChatCompletionAudioParam | null; - - /** - * Number between -2.0 and 2.0. Positive values penalize new tokens based on their - * existing frequency in the text so far, decreasing the model's likelihood to - * repeat the same line verbatim. - */ - frequency_penalty?: number | null; - - /** - * Deprecated in favor of `tool_choice`. - * - * Controls which (if any) function is called by the model. - * - * `none` means the model will not call a function and instead generates a message. - * - * `auto` means the model can pick between generating a message or calling a - * function. - * - * Specifying a particular function via `{"name": "my_function"}` forces the model - * to call that function. - * - * `none` is the default when no functions are present. `auto` is the default if - * functions are present. - */ - function_call?: 'none' | 'auto' | ChatCompletionFunctionCallOption; - - /** - * Deprecated in favor of `tools`. - * - * A list of functions the model may generate JSON inputs for. - */ - functions?: Array; - - /** - * Modify the likelihood of specified tokens appearing in the completion. - * - * Accepts a JSON object that maps tokens (specified by their token ID in the - * tokenizer) to an associated bias value from -100 to 100. Mathematically, the - * bias is added to the logits generated by the model prior to sampling. The exact - * effect will vary per model, but values between -1 and 1 should decrease or - * increase likelihood of selection; values like -100 or 100 should result in a ban - * or exclusive selection of the relevant token. - */ - logit_bias?: Record | null; - - /** - * Whether to return log probabilities of the output tokens or not. If true, - * returns the log probabilities of each output token returned in the `content` of - * `message`. - */ - logprobs?: boolean | null; - - /** - * An upper bound for the number of tokens that can be generated for a completion, - * including visible output tokens and - * [reasoning tokens](https://platform.openai.com/docs/guides/reasoning). - */ - max_completion_tokens?: number | null; - - /** - * The maximum number of [tokens](/tokenizer) that can be generated in the chat - * completion. This value can be used to control - * [costs](https://openai.com/api/pricing/) for text generated via API. - * - * This value is now deprecated in favor of `max_completion_tokens`, and is not - * compatible with - * [o1 series models](https://platform.openai.com/docs/guides/reasoning). - */ - max_tokens?: number | null; - - /** - * Developer-defined tags and values used for filtering completions in the - * [dashboard](https://platform.openai.com/chat-completions). - */ - metadata?: Record | null; - - /** - * Output types that you would like the model to generate for this request. Most - * models are capable of generating text, which is the default: - * - * `["text"]` - * - * The `gpt-4o-audio-preview` model can also be used to - * [generate audio](https://platform.openai.com/docs/guides/audio). To request that - * this model generate both text and audio responses, you can use: - * - * `["text", "audio"]` - */ - modalities?: Array | null; - - /** - * How many chat completion choices to generate for each input message. Note that - * you will be charged based on the number of generated tokens across all of the - * choices. Keep `n` as `1` to minimize costs. - */ - n?: number | null; - - /** - * Whether to enable - * [parallel function calling](https://platform.openai.com/docs/guides/function-calling#configuring-parallel-function-calling) - * during tool use. - */ - parallel_tool_calls?: boolean; - - /** - * Static predicted output content, such as the content of a text file that is - * being regenerated. - */ - prediction?: ChatCompletionPredictionContent | null; - - /** - * Number between -2.0 and 2.0. Positive values penalize new tokens based on - * whether they appear in the text so far, increasing the model's likelihood to - * talk about new topics. - */ - presence_penalty?: number | null; - - /** - * **o1 models only** - * - * Constrains effort on reasoning for - * [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently - * supported values are `low`, `medium`, and `high`. Reducing reasoning effort can - * result in faster responses and fewer tokens used on reasoning in a response. - */ - reasoning_effort?: ChatCompletionReasoningEffort; - - /** - * An object specifying the format that the model must output. - * - * Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured - * Outputs which ensures the model will match your supplied JSON schema. Learn more - * in the - * [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). - * - * Setting to `{ "type": "json_object" }` enables JSON mode, which ensures the - * message the model generates is valid JSON. - * - * **Important:** when using JSON mode, you **must** also instruct the model to - * produce JSON yourself via a system or user message. Without this, the model may - * generate an unending stream of whitespace until the generation reaches the token - * limit, resulting in a long-running and seemingly "stuck" request. Also note that - * the message content may be partially cut off if `finish_reason="length"`, which - * indicates the generation exceeded `max_tokens` or the conversation exceeded the - * max context length. - */ - response_format?: - | Shared.ResponseFormatText - | Shared.ResponseFormatJSONObject - | Shared.ResponseFormatJSONSchema; - - /** - * This feature is in Beta. If specified, our system will make a best effort to - * sample deterministically, such that repeated requests with the same `seed` and - * parameters should return the same result. Determinism is not guaranteed, and you - * should refer to the `system_fingerprint` response parameter to monitor changes - * in the backend. - */ - seed?: number | null; - - /** - * Specifies the latency tier to use for processing the request. This parameter is - * relevant for customers subscribed to the scale tier service: - * - * - If set to 'auto', and the Project is Scale tier enabled, the system will - * utilize scale tier credits until they are exhausted. - * - If set to 'auto', and the Project is not Scale tier enabled, the request will - * be processed using the default service tier with a lower uptime SLA and no - * latency guarentee. - * - If set to 'default', the request will be processed using the default service - * tier with a lower uptime SLA and no latency guarentee. - * - When not set, the default behavior is 'auto'. - * - * When this parameter is set, the response body will include the `service_tier` - * utilized. - */ - service_tier?: 'auto' | 'default' | null; - - /** - * Up to 4 sequences where the API will stop generating further tokens. - */ - stop?: string | null | Array; - - /** - * Whether or not to store the output of this chat completion request for use in - * our [model distillation](https://platform.openai.com/docs/guides/distillation) - * or [evals](https://platform.openai.com/docs/guides/evals) products. - */ - store?: boolean | null; - - /** - * If set, partial message deltas will be sent, like in ChatGPT. Tokens will be - * sent as data-only - * [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format) - * as they become available, with the stream terminated by a `data: [DONE]` - * message. - * [Example Python code](https://cookbook.openai.com/examples/how_to_stream_completions). - */ - stream?: boolean | null; - - /** - * Options for streaming response. Only set this when you set `stream: true`. - */ - stream_options?: ChatCompletionStreamOptions | null; - - /** - * What sampling temperature to use, between 0 and 2. Higher values like 0.8 will - * make the output more random, while lower values like 0.2 will make it more - * focused and deterministic. We generally recommend altering this or `top_p` but - * not both. - */ - temperature?: number | null; - - /** - * Controls which (if any) tool is called by the model. `none` means the model will - * not call any tool and instead generates a message. `auto` means the model can - * pick between generating a message or calling one or more tools. `required` means - * the model must call one or more tools. Specifying a particular tool via - * `{"type": "function", "function": {"name": "my_function"}}` forces the model to - * call that tool. - * - * `none` is the default when no tools are present. `auto` is the default if tools - * are present. - */ - tool_choice?: ChatCompletionToolChoiceOption; - - /** - * A list of tools the model may call. Currently, only functions are supported as a - * tool. Use this to provide a list of functions the model may generate JSON inputs - * for. A max of 128 functions are supported. - */ - tools?: Array; - - /** - * An integer between 0 and 20 specifying the number of most likely tokens to - * return at each token position, each with an associated log probability. - * `logprobs` must be set to `true` if this parameter is used. - */ - top_logprobs?: number | null; - - /** - * An alternative to sampling with temperature, called nucleus sampling, where the - * model considers the results of the tokens with top_p probability mass. So 0.1 - * means only the tokens comprising the top 10% probability mass are considered. - * - * We generally recommend altering this or `temperature` but not both. - */ - top_p?: number | null; - - /** - * A unique identifier representing your end-user, which can help OpenAI to monitor - * and detect abuse. - * [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). - */ - user?: string; -} - -export namespace ChatCompletionCreateParams { - /** - * @deprecated - */ - export interface Function { - /** - * The name of the function to be called. Must be a-z, A-Z, 0-9, or contain - * underscores and dashes, with a maximum length of 64. - */ - name: string; - - /** - * A description of what the function does, used by the model to choose when and - * how to call the function. - */ - description?: string; - - /** - * The parameters the functions accepts, described as a JSON Schema object. See the - * [guide](https://platform.openai.com/docs/guides/function-calling) for examples, - * and the - * [JSON Schema reference](https://json-schema.org/understanding-json-schema/) for - * documentation about the format. - * - * Omitting `parameters` defines a function with an empty parameter list. - */ - parameters?: Shared.FunctionParameters; - } - - export type ChatCompletionCreateParamsNonStreaming = - ChatCompletionsAPI.ChatCompletionCreateParamsNonStreaming; - export type ChatCompletionCreateParamsStreaming = ChatCompletionsAPI.ChatCompletionCreateParamsStreaming; -} - -/** - * @deprecated Use ChatCompletionCreateParams instead - */ -export type CompletionCreateParams = ChatCompletionCreateParams; - -export interface ChatCompletionCreateParamsNonStreaming extends ChatCompletionCreateParamsBase { - /** - * If set, partial message deltas will be sent, like in ChatGPT. Tokens will be - * sent as data-only - * [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format) - * as they become available, with the stream terminated by a `data: [DONE]` - * message. - * [Example Python code](https://cookbook.openai.com/examples/how_to_stream_completions). - */ - stream?: false | null; -} - -/** - * @deprecated Use ChatCompletionCreateParamsNonStreaming instead - */ -export type CompletionCreateParamsNonStreaming = ChatCompletionCreateParamsNonStreaming; - -export interface ChatCompletionCreateParamsStreaming extends ChatCompletionCreateParamsBase { - /** - * If set, partial message deltas will be sent, like in ChatGPT. Tokens will be - * sent as data-only - * [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format) - * as they become available, with the stream terminated by a `data: [DONE]` - * message. - * [Example Python code](https://cookbook.openai.com/examples/how_to_stream_completions). - */ - stream: true; -} - -/** - * @deprecated Use ChatCompletionCreateParamsStreaming instead - */ -export type CompletionCreateParamsStreaming = ChatCompletionCreateParamsStreaming; - -export declare namespace Completions { - export { - type ChatCompletion as ChatCompletion, - type ChatCompletionAssistantMessageParam as ChatCompletionAssistantMessageParam, - type ChatCompletionAudio as ChatCompletionAudio, - type ChatCompletionAudioParam as ChatCompletionAudioParam, - type ChatCompletionChunk as ChatCompletionChunk, - type ChatCompletionContentPart as ChatCompletionContentPart, - type ChatCompletionContentPartImage as ChatCompletionContentPartImage, - type ChatCompletionContentPartInputAudio as ChatCompletionContentPartInputAudio, - type ChatCompletionContentPartRefusal as ChatCompletionContentPartRefusal, - type ChatCompletionContentPartText as ChatCompletionContentPartText, - type ChatCompletionDeveloperMessageParam as ChatCompletionDeveloperMessageParam, - type ChatCompletionFunctionCallOption as ChatCompletionFunctionCallOption, - type ChatCompletionFunctionMessageParam as ChatCompletionFunctionMessageParam, - type ChatCompletionMessage as ChatCompletionMessage, - type ChatCompletionMessageParam as ChatCompletionMessageParam, - type ChatCompletionMessageToolCall as ChatCompletionMessageToolCall, - type ChatCompletionModality as ChatCompletionModality, - type ChatCompletionNamedToolChoice as ChatCompletionNamedToolChoice, - type ChatCompletionPredictionContent as ChatCompletionPredictionContent, - type ChatCompletionReasoningEffort as ChatCompletionReasoningEffort, - type ChatCompletionRole as ChatCompletionRole, - type ChatCompletionStreamOptions as ChatCompletionStreamOptions, - type ChatCompletionSystemMessageParam as ChatCompletionSystemMessageParam, - type ChatCompletionTokenLogprob as ChatCompletionTokenLogprob, - type ChatCompletionTool as ChatCompletionTool, - type ChatCompletionToolChoiceOption as ChatCompletionToolChoiceOption, - type ChatCompletionToolMessageParam as ChatCompletionToolMessageParam, - type ChatCompletionUserMessageParam as ChatCompletionUserMessageParam, - type CreateChatCompletionRequestMessage as CreateChatCompletionRequestMessage, - type ChatCompletionCreateParams as ChatCompletionCreateParams, - type CompletionCreateParams as CompletionCreateParams, - type ChatCompletionCreateParamsNonStreaming as ChatCompletionCreateParamsNonStreaming, - type CompletionCreateParamsNonStreaming as CompletionCreateParamsNonStreaming, - type ChatCompletionCreateParamsStreaming as ChatCompletionCreateParamsStreaming, - type CompletionCreateParamsStreaming as CompletionCreateParamsStreaming, - }; -} +export * from './completions/completions'; diff --git a/src/resources/chat/completions/completions.ts b/src/resources/chat/completions/completions.ts new file mode 100644 index 000000000..29c9ad390 --- /dev/null +++ b/src/resources/chat/completions/completions.ts @@ -0,0 +1,1405 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../../../resource'; +import * as CompletionsCompletionsAPI from './completions'; +import * as CompletionsAPI from '../../completions'; +import * as Shared from '../../shared'; +import * as ChatAPI from '../chat'; +import * as MessagesAPI from './messages'; +import { MessageListParams, Messages } from './messages'; +import { APIPromise } from '../../../api-promise'; +import { CursorPage, type CursorPageParams, PagePromise } from '../../../pagination'; +import { Stream } from '../../../streaming'; +import { RequestOptions } from '../../../internal/request-options'; +import { path } from '../../../internal/utils/path'; + +export class Completions extends APIResource { + messages: MessagesAPI.Messages = new MessagesAPI.Messages(this._client); + + /** + * Creates a model response for the given chat conversation. Learn more in the + * [text generation](https://platform.openai.com/docs/guides/text-generation), + * [vision](https://platform.openai.com/docs/guides/vision), and + * [audio](https://platform.openai.com/docs/guides/audio) guides. + * + * Parameter support can differ depending on the model used to generate the + * response, particularly for newer reasoning models. Parameters that are only + * supported for reasoning models are noted below. For the current state of + * unsupported parameters in reasoning models, + * [refer to the reasoning guide](https://platform.openai.com/docs/guides/reasoning). + */ + create(body: ChatCompletionCreateParamsNonStreaming, options?: RequestOptions): APIPromise; + create( + body: ChatCompletionCreateParamsStreaming, + options?: RequestOptions, + ): APIPromise>; + create( + body: ChatCompletionCreateParamsBase, + options?: RequestOptions, + ): APIPromise | ChatCompletion>; + create( + body: ChatCompletionCreateParams, + options?: RequestOptions, + ): APIPromise | APIPromise> { + return this._client.post('/chat/completions', { body, ...options, stream: body.stream ?? false }) as + | APIPromise + | APIPromise>; + } + + /** + * Get a stored chat completion. Only chat completions that have been created with + * the `store` parameter set to `true` will be returned. + */ + retrieve(completionID: string, options?: RequestOptions): APIPromise { + return this._client.get(path`/chat/completions/${completionID}`, options); + } + + /** + * Modify a stored chat completion. Only chat completions that have been created + * with the `store` parameter set to `true` can be modified. Currently, the only + * supported modification is to update the `metadata` field. + */ + update( + completionID: string, + body: ChatCompletionUpdateParams, + options?: RequestOptions, + ): APIPromise { + return this._client.post(path`/chat/completions/${completionID}`, { body, ...options }); + } + + /** + * List stored chat completions. Only chat completions that have been stored with + * the `store` parameter set to `true` will be returned. + */ + list( + query: ChatCompletionListParams | null | undefined = {}, + options?: RequestOptions, + ): PagePromise { + return this._client.getAPIList('/chat/completions', CursorPage, { query, ...options }); + } + + /** + * Delete a stored chat completion. Only chat completions that have been created + * with the `store` parameter set to `true` can be deleted. + */ + delete(completionID: string, options?: RequestOptions): APIPromise { + return this._client.delete(path`/chat/completions/${completionID}`, options); + } +} + +export type ChatCompletionsPage = CursorPage; + +export type ChatCompletionStoreMessagesPage = CursorPage; + +/** + * Represents a chat completion response returned by model, based on the provided + * input. + */ +export interface ChatCompletion { + /** + * A unique identifier for the chat completion. + */ + id: string; + + /** + * A list of chat completion choices. Can be more than one if `n` is greater + * than 1. + */ + choices: Array; + + /** + * The Unix timestamp (in seconds) of when the chat completion was created. + */ + created: number; + + /** + * The model used for the chat completion. + */ + model: string; + + /** + * The object type, which is always `chat.completion`. + */ + object: 'chat.completion'; + + /** + * The service tier used for processing the request. + */ + service_tier?: 'scale' | 'default' | null; + + /** + * This fingerprint represents the backend configuration that the model runs with. + * + * Can be used in conjunction with the `seed` request parameter to understand when + * backend changes have been made that might impact determinism. + */ + system_fingerprint?: string; + + /** + * Usage statistics for the completion request. + */ + usage?: CompletionsAPI.CompletionUsage; +} + +export namespace ChatCompletion { + export interface Choice { + /** + * The reason the model stopped generating tokens. This will be `stop` if the model + * hit a natural stop point or a provided stop sequence, `length` if the maximum + * number of tokens specified in the request was reached, `content_filter` if + * content was omitted due to a flag from our content filters, `tool_calls` if the + * model called a tool, or `function_call` (deprecated) if the model called a + * function. + */ + finish_reason: 'stop' | 'length' | 'tool_calls' | 'content_filter' | 'function_call'; + + /** + * The index of the choice in the list of choices. + */ + index: number; + + /** + * Log probability information for the choice. + */ + logprobs: Choice.Logprobs | null; + + /** + * A chat completion message generated by the model. + */ + message: CompletionsCompletionsAPI.ChatCompletionMessage; + } + + export namespace Choice { + /** + * Log probability information for the choice. + */ + export interface Logprobs { + /** + * A list of message content tokens with log probability information. + */ + content: Array | null; + + /** + * A list of message refusal tokens with log probability information. + */ + refusal: Array | null; + } + } +} + +/** + * Messages sent by the model in response to user messages. + */ +export interface ChatCompletionAssistantMessageParam { + /** + * The role of the messages author, in this case `assistant`. + */ + role: 'assistant'; + + /** + * Data about a previous audio response from the model. + * [Learn more](https://platform.openai.com/docs/guides/audio). + */ + audio?: ChatCompletionAssistantMessageParam.Audio | null; + + /** + * The contents of the assistant message. Required unless `tool_calls` or + * `function_call` is specified. + */ + content?: string | Array | null; + + /** + * @deprecated Deprecated and replaced by `tool_calls`. The name and arguments of a + * function that should be called, as generated by the model. + */ + function_call?: ChatCompletionAssistantMessageParam.FunctionCall | null; + + /** + * An optional name for the participant. Provides the model information to + * differentiate between participants of the same role. + */ + name?: string; + + /** + * The refusal message by the assistant. + */ + refusal?: string | null; + + /** + * The tool calls generated by the model, such as function calls. + */ + tool_calls?: Array; +} + +export namespace ChatCompletionAssistantMessageParam { + /** + * Data about a previous audio response from the model. + * [Learn more](https://platform.openai.com/docs/guides/audio). + */ + export interface Audio { + /** + * Unique identifier for a previous audio response from the model. + */ + id: string; + } + + /** + * @deprecated Deprecated and replaced by `tool_calls`. The name and arguments of a + * function that should be called, as generated by the model. + */ + export interface FunctionCall { + /** + * The arguments to call the function with, as generated by the model in JSON + * format. Note that the model does not always generate valid JSON, and may + * hallucinate parameters not defined by your function schema. Validate the + * arguments in your code before calling your function. + */ + arguments: string; + + /** + * The name of the function to call. + */ + name: string; + } +} + +/** + * If the audio output modality is requested, this object contains data about the + * audio response from the model. + * [Learn more](https://platform.openai.com/docs/guides/audio). + */ +export interface ChatCompletionAudio { + /** + * Unique identifier for this audio response. + */ + id: string; + + /** + * Base64 encoded audio bytes generated by the model, in the format specified in + * the request. + */ + data: string; + + /** + * The Unix timestamp (in seconds) for when this audio response will no longer be + * accessible on the server for use in multi-turn conversations. + */ + expires_at: number; + + /** + * Transcript of the audio generated by the model. + */ + transcript: string; +} + +/** + * Parameters for audio output. Required when audio output is requested with + * `modalities: ["audio"]`. + * [Learn more](https://platform.openai.com/docs/guides/audio). + */ +export interface ChatCompletionAudioParam { + /** + * Specifies the output audio format. Must be one of `wav`, `mp3`, `flac`, `opus`, + * or `pcm16`. + */ + format: 'wav' | 'mp3' | 'flac' | 'opus' | 'pcm16'; + + /** + * The voice the model uses to respond. Supported voices are `ash`, `ballad`, + * `coral`, `sage`, and `verse` (also supported but not recommended are `alloy`, + * `echo`, and `shimmer`; these voices are less expressive). + */ + voice: 'alloy' | 'ash' | 'ballad' | 'coral' | 'echo' | 'sage' | 'shimmer' | 'verse'; +} + +/** + * Represents a streamed chunk of a chat completion response returned by model, + * based on the provided input. + */ +export interface ChatCompletionChunk { + /** + * A unique identifier for the chat completion. Each chunk has the same ID. + */ + id: string; + + /** + * A list of chat completion choices. Can contain more than one elements if `n` is + * greater than 1. Can also be empty for the last chunk if you set + * `stream_options: {"include_usage": true}`. + */ + choices: Array; + + /** + * The Unix timestamp (in seconds) of when the chat completion was created. Each + * chunk has the same timestamp. + */ + created: number; + + /** + * The model to generate the completion. + */ + model: string; + + /** + * The object type, which is always `chat.completion.chunk`. + */ + object: 'chat.completion.chunk'; + + /** + * The service tier used for processing the request. + */ + service_tier?: 'scale' | 'default' | null; + + /** + * This fingerprint represents the backend configuration that the model runs with. + * Can be used in conjunction with the `seed` request parameter to understand when + * backend changes have been made that might impact determinism. + */ + system_fingerprint?: string; + + /** + * An optional field that will only be present when you set + * `stream_options: {"include_usage": true}` in your request. When present, it + * contains a null value except for the last chunk which contains the token usage + * statistics for the entire request. + */ + usage?: CompletionsAPI.CompletionUsage | null; +} + +export namespace ChatCompletionChunk { + export interface Choice { + /** + * A chat completion delta generated by streamed model responses. + */ + delta: Choice.Delta; + + /** + * The reason the model stopped generating tokens. This will be `stop` if the model + * hit a natural stop point or a provided stop sequence, `length` if the maximum + * number of tokens specified in the request was reached, `content_filter` if + * content was omitted due to a flag from our content filters, `tool_calls` if the + * model called a tool, or `function_call` (deprecated) if the model called a + * function. + */ + finish_reason: 'stop' | 'length' | 'tool_calls' | 'content_filter' | 'function_call' | null; + + /** + * The index of the choice in the list of choices. + */ + index: number; + + /** + * Log probability information for the choice. + */ + logprobs?: Choice.Logprobs | null; + } + + export namespace Choice { + /** + * A chat completion delta generated by streamed model responses. + */ + export interface Delta { + /** + * The contents of the chunk message. + */ + content?: string | null; + + /** + * @deprecated Deprecated and replaced by `tool_calls`. The name and arguments of a + * function that should be called, as generated by the model. + */ + function_call?: Delta.FunctionCall; + + /** + * The refusal message generated by the model. + */ + refusal?: string | null; + + /** + * The role of the author of this message. + */ + role?: 'developer' | 'system' | 'user' | 'assistant' | 'tool'; + + tool_calls?: Array; + } + + export namespace Delta { + /** + * @deprecated Deprecated and replaced by `tool_calls`. The name and arguments of a + * function that should be called, as generated by the model. + */ + export interface FunctionCall { + /** + * The arguments to call the function with, as generated by the model in JSON + * format. Note that the model does not always generate valid JSON, and may + * hallucinate parameters not defined by your function schema. Validate the + * arguments in your code before calling your function. + */ + arguments?: string; + + /** + * The name of the function to call. + */ + name?: string; + } + + export interface ToolCall { + index: number; + + /** + * The ID of the tool call. + */ + id?: string; + + function?: ToolCall.Function; + + /** + * The type of the tool. Currently, only `function` is supported. + */ + type?: 'function'; + } + + export namespace ToolCall { + export interface Function { + /** + * The arguments to call the function with, as generated by the model in JSON + * format. Note that the model does not always generate valid JSON, and may + * hallucinate parameters not defined by your function schema. Validate the + * arguments in your code before calling your function. + */ + arguments?: string; + + /** + * The name of the function to call. + */ + name?: string; + } + } + } + + /** + * Log probability information for the choice. + */ + export interface Logprobs { + /** + * A list of message content tokens with log probability information. + */ + content: Array | null; + + /** + * A list of message refusal tokens with log probability information. + */ + refusal: Array | null; + } + } +} + +/** + * Learn about + * [text inputs](https://platform.openai.com/docs/guides/text-generation). + */ +export type ChatCompletionContentPart = + | ChatCompletionContentPartText + | ChatCompletionContentPartImage + | ChatCompletionContentPartInputAudio; + +/** + * Learn about [image inputs](https://platform.openai.com/docs/guides/vision). + */ +export interface ChatCompletionContentPartImage { + image_url: ChatCompletionContentPartImage.ImageURL; + + /** + * The type of the content part. + */ + type: 'image_url'; +} + +export namespace ChatCompletionContentPartImage { + export interface ImageURL { + /** + * Either a URL of the image or the base64 encoded image data. + */ + url: string; + + /** + * Specifies the detail level of the image. Learn more in the + * [Vision guide](https://platform.openai.com/docs/guides/vision#low-or-high-fidelity-image-understanding). + */ + detail?: 'auto' | 'low' | 'high'; + } +} + +/** + * Learn about [audio inputs](https://platform.openai.com/docs/guides/audio). + */ +export interface ChatCompletionContentPartInputAudio { + input_audio: ChatCompletionContentPartInputAudio.InputAudio; + + /** + * The type of the content part. Always `input_audio`. + */ + type: 'input_audio'; +} + +export namespace ChatCompletionContentPartInputAudio { + export interface InputAudio { + /** + * Base64 encoded audio data. + */ + data: string; + + /** + * The format of the encoded audio data. Currently supports "wav" and "mp3". + */ + format: 'wav' | 'mp3'; + } +} + +export interface ChatCompletionContentPartRefusal { + /** + * The refusal message generated by the model. + */ + refusal: string; + + /** + * The type of the content part. + */ + type: 'refusal'; +} + +/** + * Learn about + * [text inputs](https://platform.openai.com/docs/guides/text-generation). + */ +export interface ChatCompletionContentPartText { + /** + * The text content. + */ + text: string; + + /** + * The type of the content part. + */ + type: 'text'; +} + +export interface ChatCompletionDeleted { + /** + * The ID of the chat completion that was deleted. + */ + id: string; + + /** + * Whether the chat completion was deleted. + */ + deleted: boolean; + + /** + * The type of object being deleted. + */ + object: 'chat.completion.deleted'; +} + +/** + * Developer-provided instructions that the model should follow, regardless of + * messages sent by the user. With o1 models and newer, `developer` messages + * replace the previous `system` messages. + */ +export interface ChatCompletionDeveloperMessageParam { + /** + * The contents of the developer message. + */ + content: string | Array; + + /** + * The role of the messages author, in this case `developer`. + */ + role: 'developer'; + + /** + * An optional name for the participant. Provides the model information to + * differentiate between participants of the same role. + */ + name?: string; +} + +/** + * Specifying a particular function via `{"name": "my_function"}` forces the model + * to call that function. + */ +export interface ChatCompletionFunctionCallOption { + /** + * The name of the function to call. + */ + name: string; +} + +/** + * @deprecated + */ +export interface ChatCompletionFunctionMessageParam { + /** + * The contents of the function message. + */ + content: string | null; + + /** + * The name of the function to call. + */ + name: string; + + /** + * The role of the messages author, in this case `function`. + */ + role: 'function'; +} + +/** + * A chat completion message generated by the model. + */ +export interface ChatCompletionMessage { + /** + * The contents of the message. + */ + content: string | null; + + /** + * The refusal message generated by the model. + */ + refusal: string | null; + + /** + * The role of the author of this message. + */ + role: 'assistant'; + + /** + * If the audio output modality is requested, this object contains data about the + * audio response from the model. + * [Learn more](https://platform.openai.com/docs/guides/audio). + */ + audio?: ChatCompletionAudio | null; + + /** + * @deprecated Deprecated and replaced by `tool_calls`. The name and arguments of a + * function that should be called, as generated by the model. + */ + function_call?: ChatCompletionMessage.FunctionCall | null; + + /** + * The tool calls generated by the model, such as function calls. + */ + tool_calls?: Array; +} + +export namespace ChatCompletionMessage { + /** + * @deprecated Deprecated and replaced by `tool_calls`. The name and arguments of a + * function that should be called, as generated by the model. + */ + export interface FunctionCall { + /** + * The arguments to call the function with, as generated by the model in JSON + * format. Note that the model does not always generate valid JSON, and may + * hallucinate parameters not defined by your function schema. Validate the + * arguments in your code before calling your function. + */ + arguments: string; + + /** + * The name of the function to call. + */ + name: string; + } +} + +/** + * Developer-provided instructions that the model should follow, regardless of + * messages sent by the user. With o1 models and newer, `developer` messages + * replace the previous `system` messages. + */ +export type ChatCompletionMessageParam = + | ChatCompletionDeveloperMessageParam + | ChatCompletionSystemMessageParam + | ChatCompletionUserMessageParam + | ChatCompletionAssistantMessageParam + | ChatCompletionToolMessageParam + | ChatCompletionFunctionMessageParam; + +export interface ChatCompletionMessageToolCall { + /** + * The ID of the tool call. + */ + id: string; + + /** + * The function that the model called. + */ + function: ChatCompletionMessageToolCall.Function; + + /** + * The type of the tool. Currently, only `function` is supported. + */ + type: 'function'; +} + +export namespace ChatCompletionMessageToolCall { + /** + * The function that the model called. + */ + export interface Function { + /** + * The arguments to call the function with, as generated by the model in JSON + * format. Note that the model does not always generate valid JSON, and may + * hallucinate parameters not defined by your function schema. Validate the + * arguments in your code before calling your function. + */ + arguments: string; + + /** + * The name of the function to call. + */ + name: string; + } +} + +export type ChatCompletionModality = 'text' | 'audio'; + +/** + * Specifies a tool the model should use. Use to force the model to call a specific + * function. + */ +export interface ChatCompletionNamedToolChoice { + function: ChatCompletionNamedToolChoice.Function; + + /** + * The type of the tool. Currently, only `function` is supported. + */ + type: 'function'; +} + +export namespace ChatCompletionNamedToolChoice { + export interface Function { + /** + * The name of the function to call. + */ + name: string; + } +} + +/** + * Static predicted output content, such as the content of a text file that is + * being regenerated. + */ +export interface ChatCompletionPredictionContent { + /** + * The content that should be matched when generating a model response. If + * generated tokens would match this content, the entire model response can be + * returned much more quickly. + */ + content: string | Array; + + /** + * The type of the predicted content you want to provide. This type is currently + * always `content`. + */ + type: 'content'; +} + +/** + * **o1 and o3-mini models only** + * + * Constrains effort on reasoning for + * [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently + * supported values are `low`, `medium`, and `high`. Reducing reasoning effort can + * result in faster responses and fewer tokens used on reasoning in a response. + */ +export type ChatCompletionReasoningEffort = 'low' | 'medium' | 'high' | null; + +/** + * The role of the author of a message + */ +export type ChatCompletionRole = 'developer' | 'system' | 'user' | 'assistant' | 'tool' | 'function'; + +/** + * A chat completion message generated by the model. + */ +export interface ChatCompletionStoreMessage extends ChatCompletionMessage { + /** + * The identifier of the chat message. + */ + id: string; +} + +/** + * Options for streaming response. Only set this when you set `stream: true`. + */ +export interface ChatCompletionStreamOptions { + /** + * If set, an additional chunk will be streamed before the `data: [DONE]` message. + * The `usage` field on this chunk shows the token usage statistics for the entire + * request, and the `choices` field will always be an empty array. All other chunks + * will also include a `usage` field, but with a null value. + */ + include_usage?: boolean; +} + +/** + * Developer-provided instructions that the model should follow, regardless of + * messages sent by the user. With o1 models and newer, use `developer` messages + * for this purpose instead. + */ +export interface ChatCompletionSystemMessageParam { + /** + * The contents of the system message. + */ + content: string | Array; + + /** + * The role of the messages author, in this case `system`. + */ + role: 'system'; + + /** + * An optional name for the participant. Provides the model information to + * differentiate between participants of the same role. + */ + name?: string; +} + +export interface ChatCompletionTokenLogprob { + /** + * The token. + */ + token: string; + + /** + * A list of integers representing the UTF-8 bytes representation of the token. + * Useful in instances where characters are represented by multiple tokens and + * their byte representations must be combined to generate the correct text + * representation. Can be `null` if there is no bytes representation for the token. + */ + bytes: Array | null; + + /** + * The log probability of this token, if it is within the top 20 most likely + * tokens. Otherwise, the value `-9999.0` is used to signify that the token is very + * unlikely. + */ + logprob: number; + + /** + * List of the most likely tokens and their log probability, at this token + * position. In rare cases, there may be fewer than the number of requested + * `top_logprobs` returned. + */ + top_logprobs: Array; +} + +export namespace ChatCompletionTokenLogprob { + export interface TopLogprob { + /** + * The token. + */ + token: string; + + /** + * A list of integers representing the UTF-8 bytes representation of the token. + * Useful in instances where characters are represented by multiple tokens and + * their byte representations must be combined to generate the correct text + * representation. Can be `null` if there is no bytes representation for the token. + */ + bytes: Array | null; + + /** + * The log probability of this token, if it is within the top 20 most likely + * tokens. Otherwise, the value `-9999.0` is used to signify that the token is very + * unlikely. + */ + logprob: number; + } +} + +export interface ChatCompletionTool { + function: Shared.FunctionDefinition; + + /** + * The type of the tool. Currently, only `function` is supported. + */ + type: 'function'; +} + +/** + * Controls which (if any) tool is called by the model. `none` means the model will + * not call any tool and instead generates a message. `auto` means the model can + * pick between generating a message or calling one or more tools. `required` means + * the model must call one or more tools. Specifying a particular tool via + * `{"type": "function", "function": {"name": "my_function"}}` forces the model to + * call that tool. + * + * `none` is the default when no tools are present. `auto` is the default if tools + * are present. + */ +export type ChatCompletionToolChoiceOption = 'none' | 'auto' | 'required' | ChatCompletionNamedToolChoice; + +export interface ChatCompletionToolMessageParam { + /** + * The contents of the tool message. + */ + content: string | Array; + + /** + * The role of the messages author, in this case `tool`. + */ + role: 'tool'; + + /** + * Tool call that this message is responding to. + */ + tool_call_id: string; +} + +/** + * Messages sent by an end user, containing prompts or additional context + * information. + */ +export interface ChatCompletionUserMessageParam { + /** + * The contents of the user message. + */ + content: string | Array; + + /** + * The role of the messages author, in this case `user`. + */ + role: 'user'; + + /** + * An optional name for the participant. Provides the model information to + * differentiate between participants of the same role. + */ + name?: string; +} + +export type ChatCompletionCreateParams = + | ChatCompletionCreateParamsNonStreaming + | ChatCompletionCreateParamsStreaming; + +export interface ChatCompletionCreateParamsBase { + /** + * A list of messages comprising the conversation so far. Depending on the + * [model](https://platform.openai.com/docs/models) you use, different message + * types (modalities) are supported, like + * [text](https://platform.openai.com/docs/guides/text-generation), + * [images](https://platform.openai.com/docs/guides/vision), and + * [audio](https://platform.openai.com/docs/guides/audio). + */ + messages: Array; + + /** + * ID of the model to use. See the + * [model endpoint compatibility](https://platform.openai.com/docs/models#model-endpoint-compatibility) + * table for details on which models work with the Chat API. + */ + model: (string & {}) | ChatAPI.ChatModel; + + /** + * Parameters for audio output. Required when audio output is requested with + * `modalities: ["audio"]`. + * [Learn more](https://platform.openai.com/docs/guides/audio). + */ + audio?: ChatCompletionAudioParam | null; + + /** + * Number between -2.0 and 2.0. Positive values penalize new tokens based on their + * existing frequency in the text so far, decreasing the model's likelihood to + * repeat the same line verbatim. + */ + frequency_penalty?: number | null; + + /** + * Deprecated in favor of `tool_choice`. + * + * Controls which (if any) function is called by the model. + * + * `none` means the model will not call a function and instead generates a message. + * + * `auto` means the model can pick between generating a message or calling a + * function. + * + * Specifying a particular function via `{"name": "my_function"}` forces the model + * to call that function. + * + * `none` is the default when no functions are present. `auto` is the default if + * functions are present. + */ + function_call?: 'none' | 'auto' | ChatCompletionFunctionCallOption; + + /** + * Deprecated in favor of `tools`. + * + * A list of functions the model may generate JSON inputs for. + */ + functions?: Array; + + /** + * Modify the likelihood of specified tokens appearing in the completion. + * + * Accepts a JSON object that maps tokens (specified by their token ID in the + * tokenizer) to an associated bias value from -100 to 100. Mathematically, the + * bias is added to the logits generated by the model prior to sampling. The exact + * effect will vary per model, but values between -1 and 1 should decrease or + * increase likelihood of selection; values like -100 or 100 should result in a ban + * or exclusive selection of the relevant token. + */ + logit_bias?: Record | null; + + /** + * Whether to return log probabilities of the output tokens or not. If true, + * returns the log probabilities of each output token returned in the `content` of + * `message`. + */ + logprobs?: boolean | null; + + /** + * An upper bound for the number of tokens that can be generated for a completion, + * including visible output tokens and + * [reasoning tokens](https://platform.openai.com/docs/guides/reasoning). + */ + max_completion_tokens?: number | null; + + /** + * The maximum number of [tokens](/tokenizer) that can be generated in the chat + * completion. This value can be used to control + * [costs](https://openai.com/api/pricing/) for text generated via API. + * + * This value is now deprecated in favor of `max_completion_tokens`, and is not + * compatible with + * [o1 series models](https://platform.openai.com/docs/guides/reasoning). + */ + max_tokens?: number | null; + + /** + * Set of 16 key-value pairs that can be attached to an object. This can be useful + * for storing additional information about the object in a structured format, and + * querying for objects via API or the dashboard. + * + * Keys are strings with a maximum length of 64 characters. Values are strings with + * a maximum length of 512 characters. + */ + metadata?: Shared.Metadata | null; + + /** + * Output types that you would like the model to generate for this request. Most + * models are capable of generating text, which is the default: + * + * `["text"]` + * + * The `gpt-4o-audio-preview` model can also be used to + * [generate audio](https://platform.openai.com/docs/guides/audio). To request that + * this model generate both text and audio responses, you can use: + * + * `["text", "audio"]` + */ + modalities?: Array | null; + + /** + * How many chat completion choices to generate for each input message. Note that + * you will be charged based on the number of generated tokens across all of the + * choices. Keep `n` as `1` to minimize costs. + */ + n?: number | null; + + /** + * Whether to enable + * [parallel function calling](https://platform.openai.com/docs/guides/function-calling#configuring-parallel-function-calling) + * during tool use. + */ + parallel_tool_calls?: boolean; + + /** + * Static predicted output content, such as the content of a text file that is + * being regenerated. + */ + prediction?: ChatCompletionPredictionContent | null; + + /** + * Number between -2.0 and 2.0. Positive values penalize new tokens based on + * whether they appear in the text so far, increasing the model's likelihood to + * talk about new topics. + */ + presence_penalty?: number | null; + + /** + * **o1 and o3-mini models only** + * + * Constrains effort on reasoning for + * [reasoning models](https://platform.openai.com/docs/guides/reasoning). Currently + * supported values are `low`, `medium`, and `high`. Reducing reasoning effort can + * result in faster responses and fewer tokens used on reasoning in a response. + */ + reasoning_effort?: ChatCompletionReasoningEffort | null; + + /** + * An object specifying the format that the model must output. + * + * Setting to `{ "type": "json_schema", "json_schema": {...} }` enables Structured + * Outputs which ensures the model will match your supplied JSON schema. Learn more + * in the + * [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs). + * + * Setting to `{ "type": "json_object" }` enables JSON mode, which ensures the + * message the model generates is valid JSON. + * + * **Important:** when using JSON mode, you **must** also instruct the model to + * produce JSON yourself via a system or user message. Without this, the model may + * generate an unending stream of whitespace until the generation reaches the token + * limit, resulting in a long-running and seemingly "stuck" request. Also note that + * the message content may be partially cut off if `finish_reason="length"`, which + * indicates the generation exceeded `max_tokens` or the conversation exceeded the + * max context length. + */ + response_format?: + | Shared.ResponseFormatText + | Shared.ResponseFormatJSONObject + | Shared.ResponseFormatJSONSchema; + + /** + * This feature is in Beta. If specified, our system will make a best effort to + * sample deterministically, such that repeated requests with the same `seed` and + * parameters should return the same result. Determinism is not guaranteed, and you + * should refer to the `system_fingerprint` response parameter to monitor changes + * in the backend. + */ + seed?: number | null; + + /** + * Specifies the latency tier to use for processing the request. This parameter is + * relevant for customers subscribed to the scale tier service: + * + * - If set to 'auto', and the Project is Scale tier enabled, the system will + * utilize scale tier credits until they are exhausted. + * - If set to 'auto', and the Project is not Scale tier enabled, the request will + * be processed using the default service tier with a lower uptime SLA and no + * latency guarantee. + * - If set to 'default', the request will be processed using the default service + * tier with a lower uptime SLA and no latency guarantee. + * - When not set, the default behavior is 'auto'. + */ + service_tier?: 'auto' | 'default' | null; + + /** + * Up to 4 sequences where the API will stop generating further tokens. + */ + stop?: string | null | Array; + + /** + * Whether or not to store the output of this chat completion request for use in + * our [model distillation](https://platform.openai.com/docs/guides/distillation) + * or [evals](https://platform.openai.com/docs/guides/evals) products. + */ + store?: boolean | null; + + /** + * If set, partial message deltas will be sent, like in ChatGPT. Tokens will be + * sent as data-only + * [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format) + * as they become available, with the stream terminated by a `data: [DONE]` + * message. + * [Example Python code](https://cookbook.openai.com/examples/how_to_stream_completions). + */ + stream?: boolean | null; + + /** + * Options for streaming response. Only set this when you set `stream: true`. + */ + stream_options?: ChatCompletionStreamOptions | null; + + /** + * What sampling temperature to use, between 0 and 2. Higher values like 0.8 will + * make the output more random, while lower values like 0.2 will make it more + * focused and deterministic. We generally recommend altering this or `top_p` but + * not both. + */ + temperature?: number | null; + + /** + * Controls which (if any) tool is called by the model. `none` means the model will + * not call any tool and instead generates a message. `auto` means the model can + * pick between generating a message or calling one or more tools. `required` means + * the model must call one or more tools. Specifying a particular tool via + * `{"type": "function", "function": {"name": "my_function"}}` forces the model to + * call that tool. + * + * `none` is the default when no tools are present. `auto` is the default if tools + * are present. + */ + tool_choice?: ChatCompletionToolChoiceOption; + + /** + * A list of tools the model may call. Currently, only functions are supported as a + * tool. Use this to provide a list of functions the model may generate JSON inputs + * for. A max of 128 functions are supported. + */ + tools?: Array; + + /** + * An integer between 0 and 20 specifying the number of most likely tokens to + * return at each token position, each with an associated log probability. + * `logprobs` must be set to `true` if this parameter is used. + */ + top_logprobs?: number | null; + + /** + * An alternative to sampling with temperature, called nucleus sampling, where the + * model considers the results of the tokens with top_p probability mass. So 0.1 + * means only the tokens comprising the top 10% probability mass are considered. + * + * We generally recommend altering this or `temperature` but not both. + */ + top_p?: number | null; + + /** + * A unique identifier representing your end-user, which can help OpenAI to monitor + * and detect abuse. + * [Learn more](https://platform.openai.com/docs/guides/safety-best-practices#end-user-ids). + */ + user?: string; +} + +export namespace ChatCompletionCreateParams { + /** + * @deprecated + */ + export interface Function { + /** + * The name of the function to be called. Must be a-z, A-Z, 0-9, or contain + * underscores and dashes, with a maximum length of 64. + */ + name: string; + + /** + * A description of what the function does, used by the model to choose when and + * how to call the function. + */ + description?: string; + + /** + * The parameters the functions accepts, described as a JSON Schema object. See the + * [guide](https://platform.openai.com/docs/guides/function-calling) for examples, + * and the + * [JSON Schema reference](https://json-schema.org/understanding-json-schema/) for + * documentation about the format. + * + * Omitting `parameters` defines a function with an empty parameter list. + */ + parameters?: Shared.FunctionParameters; + } + + export type ChatCompletionCreateParamsNonStreaming = + CompletionsCompletionsAPI.ChatCompletionCreateParamsNonStreaming; + export type ChatCompletionCreateParamsStreaming = + CompletionsCompletionsAPI.ChatCompletionCreateParamsStreaming; +} + +export interface ChatCompletionCreateParamsNonStreaming extends ChatCompletionCreateParamsBase { + /** + * If set, partial message deltas will be sent, like in ChatGPT. Tokens will be + * sent as data-only + * [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format) + * as they become available, with the stream terminated by a `data: [DONE]` + * message. + * [Example Python code](https://cookbook.openai.com/examples/how_to_stream_completions). + */ + stream?: false | null; +} + +export interface ChatCompletionCreateParamsStreaming extends ChatCompletionCreateParamsBase { + /** + * If set, partial message deltas will be sent, like in ChatGPT. Tokens will be + * sent as data-only + * [server-sent events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#Event_stream_format) + * as they become available, with the stream terminated by a `data: [DONE]` + * message. + * [Example Python code](https://cookbook.openai.com/examples/how_to_stream_completions). + */ + stream: true; +} + +export interface ChatCompletionUpdateParams { + /** + * Set of 16 key-value pairs that can be attached to an object. This can be useful + * for storing additional information about the object in a structured format, and + * querying for objects via API or the dashboard. + * + * Keys are strings with a maximum length of 64 characters. Values are strings with + * a maximum length of 512 characters. + */ + metadata: Shared.Metadata | null; +} + +export interface ChatCompletionListParams extends CursorPageParams { + /** + * A list of metadata keys to filter the chat completions by. Example: + * + * `metadata[key1]=value1&metadata[key2]=value2` + */ + metadata?: Shared.Metadata | null; + + /** + * The model used to generate the chat completions. + */ + model?: string; + + /** + * Sort order for chat completions by timestamp. Use `asc` for ascending order or + * `desc` for descending order. Defaults to `asc`. + */ + order?: 'asc' | 'desc'; +} + +Completions.Messages = Messages; + +export declare namespace Completions { + export { + type ChatCompletion as ChatCompletion, + type ChatCompletionAssistantMessageParam as ChatCompletionAssistantMessageParam, + type ChatCompletionAudio as ChatCompletionAudio, + type ChatCompletionAudioParam as ChatCompletionAudioParam, + type ChatCompletionChunk as ChatCompletionChunk, + type ChatCompletionContentPart as ChatCompletionContentPart, + type ChatCompletionContentPartImage as ChatCompletionContentPartImage, + type ChatCompletionContentPartInputAudio as ChatCompletionContentPartInputAudio, + type ChatCompletionContentPartRefusal as ChatCompletionContentPartRefusal, + type ChatCompletionContentPartText as ChatCompletionContentPartText, + type ChatCompletionDeleted as ChatCompletionDeleted, + type ChatCompletionDeveloperMessageParam as ChatCompletionDeveloperMessageParam, + type ChatCompletionFunctionCallOption as ChatCompletionFunctionCallOption, + type ChatCompletionFunctionMessageParam as ChatCompletionFunctionMessageParam, + type ChatCompletionMessage as ChatCompletionMessage, + type ChatCompletionMessageParam as ChatCompletionMessageParam, + type ChatCompletionMessageToolCall as ChatCompletionMessageToolCall, + type ChatCompletionModality as ChatCompletionModality, + type ChatCompletionNamedToolChoice as ChatCompletionNamedToolChoice, + type ChatCompletionPredictionContent as ChatCompletionPredictionContent, + type ChatCompletionReasoningEffort as ChatCompletionReasoningEffort, + type ChatCompletionRole as ChatCompletionRole, + type ChatCompletionStoreMessage as ChatCompletionStoreMessage, + type ChatCompletionStreamOptions as ChatCompletionStreamOptions, + type ChatCompletionSystemMessageParam as ChatCompletionSystemMessageParam, + type ChatCompletionTokenLogprob as ChatCompletionTokenLogprob, + type ChatCompletionTool as ChatCompletionTool, + type ChatCompletionToolChoiceOption as ChatCompletionToolChoiceOption, + type ChatCompletionToolMessageParam as ChatCompletionToolMessageParam, + type ChatCompletionUserMessageParam as ChatCompletionUserMessageParam, + type ChatCompletionsPage as ChatCompletionsPage, + type ChatCompletionCreateParams as ChatCompletionCreateParams, + type ChatCompletionCreateParamsNonStreaming as ChatCompletionCreateParamsNonStreaming, + type ChatCompletionCreateParamsStreaming as ChatCompletionCreateParamsStreaming, + type ChatCompletionUpdateParams as ChatCompletionUpdateParams, + type ChatCompletionListParams as ChatCompletionListParams, + }; + + export { Messages as Messages, type MessageListParams as MessageListParams }; +} diff --git a/src/resources/chat/completions/index.ts b/src/resources/chat/completions/index.ts new file mode 100644 index 000000000..6a3fdec83 --- /dev/null +++ b/src/resources/chat/completions/index.ts @@ -0,0 +1,43 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export { + Completions, + type ChatCompletion, + type ChatCompletionAssistantMessageParam, + type ChatCompletionAudio, + type ChatCompletionAudioParam, + type ChatCompletionChunk, + type ChatCompletionContentPart, + type ChatCompletionContentPartImage, + type ChatCompletionContentPartInputAudio, + type ChatCompletionContentPartRefusal, + type ChatCompletionContentPartText, + type ChatCompletionDeleted, + type ChatCompletionDeveloperMessageParam, + type ChatCompletionFunctionCallOption, + type ChatCompletionFunctionMessageParam, + type ChatCompletionMessage, + type ChatCompletionMessageParam, + type ChatCompletionMessageToolCall, + type ChatCompletionModality, + type ChatCompletionNamedToolChoice, + type ChatCompletionPredictionContent, + type ChatCompletionReasoningEffort, + type ChatCompletionRole, + type ChatCompletionStoreMessage, + type ChatCompletionStreamOptions, + type ChatCompletionSystemMessageParam, + type ChatCompletionTokenLogprob, + type ChatCompletionTool, + type ChatCompletionToolChoiceOption, + type ChatCompletionToolMessageParam, + type ChatCompletionUserMessageParam, + type ChatCompletionCreateParams, + type ChatCompletionCreateParamsNonStreaming, + type ChatCompletionCreateParamsStreaming, + type ChatCompletionUpdateParams, + type ChatCompletionListParams, + type ChatCompletionStoreMessagesPage, + type ChatCompletionsPage, +} from './completions'; +export { Messages, type MessageListParams } from './messages'; diff --git a/src/resources/chat/completions/messages.ts b/src/resources/chat/completions/messages.ts new file mode 100644 index 000000000..f00acbdfc --- /dev/null +++ b/src/resources/chat/completions/messages.ts @@ -0,0 +1,40 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../../../resource'; +import * as CompletionsAPI from './completions'; +import { ChatCompletionStoreMessagesPage } from './completions'; +import { CursorPage, type CursorPageParams, PagePromise } from '../../../pagination'; +import { RequestOptions } from '../../../internal/request-options'; +import { path } from '../../../internal/utils/path'; + +export class Messages extends APIResource { + /** + * Get the messages in a stored chat completion. Only chat completions that have + * been created with the `store` parameter set to `true` will be returned. + */ + list( + completionID: string, + query: MessageListParams | null | undefined = {}, + options?: RequestOptions, + ): PagePromise { + return this._client.getAPIList( + path`/chat/completions/${completionID}/messages`, + CursorPage, + { query, ...options }, + ); + } +} + +export interface MessageListParams extends CursorPageParams { + /** + * Sort order for messages by timestamp. Use `asc` for ascending order or `desc` + * for descending order. Defaults to `asc`. + */ + order?: 'asc' | 'desc'; +} + +export declare namespace Messages { + export { type MessageListParams as MessageListParams }; +} + +export { type ChatCompletionStoreMessagesPage }; diff --git a/src/resources/chat/index.ts b/src/resources/chat/index.ts index c3be19402..f098e5ce7 100644 --- a/src/resources/chat/index.ts +++ b/src/resources/chat/index.ts @@ -13,6 +13,7 @@ export { type ChatCompletionContentPartInputAudio, type ChatCompletionContentPartRefusal, type ChatCompletionContentPartText, + type ChatCompletionDeleted, type ChatCompletionDeveloperMessageParam, type ChatCompletionFunctionCallOption, type ChatCompletionFunctionMessageParam, @@ -24,6 +25,7 @@ export { type ChatCompletionPredictionContent, type ChatCompletionReasoningEffort, type ChatCompletionRole, + type ChatCompletionStoreMessage, type ChatCompletionStreamOptions, type ChatCompletionSystemMessageParam, type ChatCompletionTokenLogprob, @@ -31,11 +33,11 @@ export { type ChatCompletionToolChoiceOption, type ChatCompletionToolMessageParam, type ChatCompletionUserMessageParam, - type CreateChatCompletionRequestMessage, type ChatCompletionCreateParams, - type CompletionCreateParams, type ChatCompletionCreateParamsNonStreaming, - type CompletionCreateParamsNonStreaming, type ChatCompletionCreateParamsStreaming, - type CompletionCreateParamsStreaming, -} from './completions'; + type ChatCompletionUpdateParams, + type ChatCompletionListParams, + type ChatCompletionStoreMessagesPage, + type ChatCompletionsPage, +} from './completions/index'; diff --git a/src/resources/completions.ts b/src/resources/completions.ts index be75a46f0..742f682fe 100644 --- a/src/resources/completions.ts +++ b/src/resources/completions.ts @@ -1,28 +1,25 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import { APIResource } from '../resource'; -import { APIPromise } from '../core'; -import * as Core from '../core'; import * as CompletionsAPI from './completions'; -import * as ChatCompletionsAPI from './chat/completions'; +import * as CompletionsCompletionsAPI from './chat/completions/completions'; +import { APIPromise } from '../api-promise'; import { Stream } from '../streaming'; +import { RequestOptions } from '../internal/request-options'; export class Completions extends APIResource { /** * Creates a completion for the provided prompt and parameters. */ - create(body: CompletionCreateParamsNonStreaming, options?: Core.RequestOptions): APIPromise; - create( - body: CompletionCreateParamsStreaming, - options?: Core.RequestOptions, - ): APIPromise>; + create(body: CompletionCreateParamsNonStreaming, options?: RequestOptions): APIPromise; + create(body: CompletionCreateParamsStreaming, options?: RequestOptions): APIPromise>; create( body: CompletionCreateParamsBase, - options?: Core.RequestOptions, + options?: RequestOptions, ): APIPromise | Completion>; create( body: CompletionCreateParams, - options?: Core.RequestOptions, + options?: RequestOptions, ): APIPromise | APIPromise> { return this._client.post('/completions', { body, ...options, stream: body.stream ?? false }) as | APIPromise @@ -311,7 +308,7 @@ export interface CompletionCreateParamsBase { /** * Options for streaming response. Only set this when you set `stream: true`. */ - stream_options?: ChatCompletionsAPI.ChatCompletionStreamOptions | null; + stream_options?: CompletionsCompletionsAPI.ChatCompletionStreamOptions | null; /** * The suffix that comes after a completion of inserted text. diff --git a/src/resources/embeddings.ts b/src/resources/embeddings.ts index 4b1644a68..dcd542a1a 100644 --- a/src/resources/embeddings.ts +++ b/src/resources/embeddings.ts @@ -1,16 +1,14 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import { APIResource } from '../resource'; -import * as Core from '../core'; +import { APIPromise } from '../api-promise'; +import { RequestOptions } from '../internal/request-options'; export class Embeddings extends APIResource { /** * Creates an embedding vector representing the input text. */ - create( - body: EmbeddingCreateParams, - options?: Core.RequestOptions, - ): Core.APIPromise { + create(body: EmbeddingCreateParams, options?: RequestOptions): APIPromise { return this._client.post('/embeddings', { body, ...options }); } } @@ -86,7 +84,8 @@ export interface EmbeddingCreateParams { * `text-embedding-ada-002`), cannot be an empty string, and any array must be 2048 * dimensions or less. * [Example Python code](https://cookbook.openai.com/examples/how_to_count_tokens_with_tiktoken) - * for counting tokens. + * for counting tokens. Some models may also impose a limit on total number of + * tokens summed across inputs. */ input: string | Array | Array | Array>; diff --git a/src/resources/files.ts b/src/resources/files.ts index 42a7bdfba..56bafc224 100644 --- a/src/resources/files.ts +++ b/src/resources/files.ts @@ -1,12 +1,15 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import { APIResource } from '../resource'; -import { isRequestOptions } from '../core'; -import { sleep } from '../core'; +import { APIPromise } from '../api-promise'; +import { CursorPage, type CursorPageParams, PagePromise } from '../pagination'; +import { type Uploadable } from '../uploads'; +import { buildHeaders } from '../internal/headers'; +import { RequestOptions } from '../internal/request-options'; +import { sleep } from '../internal/utils/sleep'; import { APIConnectionTimeoutError } from '../error'; -import * as Core from '../core'; -import { CursorPage, type CursorPageParams } from '../pagination'; -import { type Response } from '../_shims/index'; +import { multipartFormRequestOptions } from '../internal/uploads'; +import { path } from '../internal/utils/path'; export class Files extends APIResource { /** @@ -32,55 +35,42 @@ export class Files extends APIResource { * Please [contact us](https://help.openai.com/) if you need to increase these * storage limits. */ - create(body: FileCreateParams, options?: Core.RequestOptions): Core.APIPromise { - return this._client.post('/files', Core.multipartFormRequestOptions({ body, ...options })); + create(body: FileCreateParams, options?: RequestOptions): APIPromise { + return this._client.post('/files', multipartFormRequestOptions({ body, ...options }, this._client)); } /** * Returns information about a specific file. */ - retrieve(fileId: string, options?: Core.RequestOptions): Core.APIPromise { - return this._client.get(`/files/${fileId}`, options); + retrieve(fileID: string, options?: RequestOptions): APIPromise { + return this._client.get(path`/files/${fileID}`, options); } /** * Returns a list of files. */ - list(query?: FileListParams, options?: Core.RequestOptions): Core.PagePromise; - list(options?: Core.RequestOptions): Core.PagePromise; list( - query: FileListParams | Core.RequestOptions = {}, - options?: Core.RequestOptions, - ): Core.PagePromise { - if (isRequestOptions(query)) { - return this.list({}, query); - } - return this._client.getAPIList('/files', FileObjectsPage, { query, ...options }); + query: FileListParams | null | undefined = {}, + options?: RequestOptions, + ): PagePromise { + return this._client.getAPIList('/files', CursorPage, { query, ...options }); } /** * Delete a file. */ - del(fileId: string, options?: Core.RequestOptions): Core.APIPromise { - return this._client.delete(`/files/${fileId}`, options); + delete(fileID: string, options?: RequestOptions): APIPromise { + return this._client.delete(path`/files/${fileID}`, options); } /** * Returns the contents of the specified file. */ - content(fileId: string, options?: Core.RequestOptions): Core.APIPromise { - return this._client.get(`/files/${fileId}/content`, { ...options, __binaryResponse: true }); - } - - /** - * Returns the contents of the specified file. - * - * @deprecated The `.content()` method should be used instead - */ - retrieveContent(fileId: string, options?: Core.RequestOptions): Core.APIPromise { - return this._client.get(`/files/${fileId}/content`, { + content(fileID: string, options?: RequestOptions): APIPromise { + return this._client.get(path`/files/${fileID}/content`, { ...options, - headers: { Accept: 'application/json', ...options?.headers }, + headers: buildHeaders([{ Accept: 'application/binary' }, options?.headers]), + __binaryResponse: true, }); } @@ -111,7 +101,7 @@ export class Files extends APIResource { } } -export class FileObjectsPage extends CursorPage {} +export type FileObjectsPage = CursorPage; export type FileContent = string; @@ -167,13 +157,18 @@ export interface FileObject { | 'vision'; /** - * @deprecated: Deprecated. The current status of the file, which can be either + * @deprecated Deprecated. The current status of the file, which can be either * `uploaded`, `processed`, or `error`. */ status: 'uploaded' | 'processed' | 'error'; /** - * @deprecated: Deprecated. For details on why a fine-tuning training file failed + * The Unix timestamp (in seconds) for when the file will expire. + */ + expires_at?: number; + + /** + * @deprecated Deprecated. For details on why a fine-tuning training file failed * validation, see the `error` field on `fine_tuning.job`. */ status_details?: string; @@ -195,7 +190,7 @@ export interface FileCreateParams { /** * The File object (not file name) to be uploaded. */ - file: Core.Uploadable; + file: Uploadable; /** * The intended purpose of the uploaded file. @@ -223,15 +218,13 @@ export interface FileListParams extends CursorPageParams { purpose?: string; } -Files.FileObjectsPage = FileObjectsPage; - export declare namespace Files { export { type FileContent as FileContent, type FileDeleted as FileDeleted, type FileObject as FileObject, type FilePurpose as FilePurpose, - FileObjectsPage as FileObjectsPage, + type FileObjectsPage as FileObjectsPage, type FileCreateParams as FileCreateParams, type FileListParams as FileListParams, }; diff --git a/src/resources/fine-tuning/fine-tuning.ts b/src/resources/fine-tuning/fine-tuning.ts index df013c8ec..9d027b72d 100644 --- a/src/resources/fine-tuning/fine-tuning.ts +++ b/src/resources/fine-tuning/fine-tuning.ts @@ -21,8 +21,6 @@ export class FineTuning extends APIResource { } FineTuning.Jobs = Jobs; -FineTuning.FineTuningJobsPage = FineTuningJobsPage; -FineTuning.FineTuningJobEventsPage = FineTuningJobEventsPage; export declare namespace FineTuning { export { @@ -32,8 +30,8 @@ export declare namespace FineTuning { type FineTuningJobIntegration as FineTuningJobIntegration, type FineTuningJobWandbIntegration as FineTuningJobWandbIntegration, type FineTuningJobWandbIntegrationObject as FineTuningJobWandbIntegrationObject, - FineTuningJobsPage as FineTuningJobsPage, - FineTuningJobEventsPage as FineTuningJobEventsPage, + type FineTuningJobsPage as FineTuningJobsPage, + type FineTuningJobEventsPage as FineTuningJobEventsPage, type JobCreateParams as JobCreateParams, type JobListParams as JobListParams, type JobListEventsParams as JobListEventsParams, diff --git a/src/resources/fine-tuning/index.ts b/src/resources/fine-tuning/index.ts index 4954406b8..898f2fc89 100644 --- a/src/resources/fine-tuning/index.ts +++ b/src/resources/fine-tuning/index.ts @@ -2,8 +2,6 @@ export { FineTuning } from './fine-tuning'; export { - FineTuningJobsPage, - FineTuningJobEventsPage, Jobs, type FineTuningJob, type FineTuningJobEvent, @@ -13,4 +11,6 @@ export { type JobCreateParams, type JobListParams, type JobListEventsParams, + type FineTuningJobsPage, + type FineTuningJobEventsPage, } from './jobs/index'; diff --git a/src/resources/fine-tuning/jobs/checkpoints.ts b/src/resources/fine-tuning/jobs/checkpoints.ts index b3018ac5f..134715cec 100644 --- a/src/resources/fine-tuning/jobs/checkpoints.ts +++ b/src/resources/fine-tuning/jobs/checkpoints.ts @@ -1,40 +1,28 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import { APIResource } from '../../../resource'; -import { isRequestOptions } from '../../../core'; -import * as Core from '../../../core'; -import { CursorPage, type CursorPageParams } from '../../../pagination'; +import { CursorPage, type CursorPageParams, PagePromise } from '../../../pagination'; +import { RequestOptions } from '../../../internal/request-options'; +import { path } from '../../../internal/utils/path'; export class Checkpoints extends APIResource { /** * List checkpoints for a fine-tuning job. */ list( - fineTuningJobId: string, - query?: CheckpointListParams, - options?: Core.RequestOptions, - ): Core.PagePromise; - list( - fineTuningJobId: string, - options?: Core.RequestOptions, - ): Core.PagePromise; - list( - fineTuningJobId: string, - query: CheckpointListParams | Core.RequestOptions = {}, - options?: Core.RequestOptions, - ): Core.PagePromise { - if (isRequestOptions(query)) { - return this.list(fineTuningJobId, {}, query); - } + fineTuningJobID: string, + query: CheckpointListParams | null | undefined = {}, + options?: RequestOptions, + ): PagePromise { return this._client.getAPIList( - `/fine_tuning/jobs/${fineTuningJobId}/checkpoints`, - FineTuningJobCheckpointsPage, + path`/fine_tuning/jobs/${fineTuningJobID}/checkpoints`, + CursorPage, { query, ...options }, ); } } -export class FineTuningJobCheckpointsPage extends CursorPage {} +export type FineTuningJobCheckpointsPage = CursorPage; /** * The `fine_tuning.job.checkpoint` object represents a model checkpoint for a @@ -100,12 +88,10 @@ export namespace FineTuningJobCheckpoint { export interface CheckpointListParams extends CursorPageParams {} -Checkpoints.FineTuningJobCheckpointsPage = FineTuningJobCheckpointsPage; - export declare namespace Checkpoints { export { type FineTuningJobCheckpoint as FineTuningJobCheckpoint, - FineTuningJobCheckpointsPage as FineTuningJobCheckpointsPage, + type FineTuningJobCheckpointsPage as FineTuningJobCheckpointsPage, type CheckpointListParams as CheckpointListParams, }; } diff --git a/src/resources/fine-tuning/jobs/index.ts b/src/resources/fine-tuning/jobs/index.ts index 7a05b48b2..4e397aea7 100644 --- a/src/resources/fine-tuning/jobs/index.ts +++ b/src/resources/fine-tuning/jobs/index.ts @@ -1,14 +1,12 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. export { - FineTuningJobCheckpointsPage, Checkpoints, type FineTuningJobCheckpoint, type CheckpointListParams, + type FineTuningJobCheckpointsPage, } from './checkpoints'; export { - FineTuningJobsPage, - FineTuningJobEventsPage, Jobs, type FineTuningJob, type FineTuningJobEvent, @@ -18,4 +16,6 @@ export { type JobCreateParams, type JobListParams, type JobListEventsParams, + type FineTuningJobsPage, + type FineTuningJobEventsPage, } from './jobs'; diff --git a/src/resources/fine-tuning/jobs/jobs.ts b/src/resources/fine-tuning/jobs/jobs.ts index 44dd011aa..51cac957c 100644 --- a/src/resources/fine-tuning/jobs/jobs.ts +++ b/src/resources/fine-tuning/jobs/jobs.ts @@ -1,8 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import { APIResource } from '../../../resource'; -import { isRequestOptions } from '../../../core'; -import * as Core from '../../../core'; import * as CheckpointsAPI from './checkpoints'; import { CheckpointListParams, @@ -10,7 +8,10 @@ import { FineTuningJobCheckpoint, FineTuningJobCheckpointsPage, } from './checkpoints'; -import { CursorPage, type CursorPageParams } from '../../../pagination'; +import { APIPromise } from '../../../api-promise'; +import { CursorPage, type CursorPageParams, PagePromise } from '../../../pagination'; +import { RequestOptions } from '../../../internal/request-options'; +import { path } from '../../../internal/utils/path'; export class Jobs extends APIResource { checkpoints: CheckpointsAPI.Checkpoints = new CheckpointsAPI.Checkpoints(this._client); @@ -24,7 +25,7 @@ export class Jobs extends APIResource { * * [Learn more about fine-tuning](https://platform.openai.com/docs/guides/fine-tuning) */ - create(body: JobCreateParams, options?: Core.RequestOptions): Core.APIPromise { + create(body: JobCreateParams, options?: RequestOptions): APIPromise { return this._client.post('/fine_tuning/jobs', { body, ...options }); } @@ -33,65 +34,46 @@ export class Jobs extends APIResource { * * [Learn more about fine-tuning](https://platform.openai.com/docs/guides/fine-tuning) */ - retrieve(fineTuningJobId: string, options?: Core.RequestOptions): Core.APIPromise { - return this._client.get(`/fine_tuning/jobs/${fineTuningJobId}`, options); + retrieve(fineTuningJobID: string, options?: RequestOptions): APIPromise { + return this._client.get(path`/fine_tuning/jobs/${fineTuningJobID}`, options); } /** * List your organization's fine-tuning jobs */ list( - query?: JobListParams, - options?: Core.RequestOptions, - ): Core.PagePromise; - list(options?: Core.RequestOptions): Core.PagePromise; - list( - query: JobListParams | Core.RequestOptions = {}, - options?: Core.RequestOptions, - ): Core.PagePromise { - if (isRequestOptions(query)) { - return this.list({}, query); - } - return this._client.getAPIList('/fine_tuning/jobs', FineTuningJobsPage, { query, ...options }); + query: JobListParams | null | undefined = {}, + options?: RequestOptions, + ): PagePromise { + return this._client.getAPIList('/fine_tuning/jobs', CursorPage, { query, ...options }); } /** * Immediately cancel a fine-tune job. */ - cancel(fineTuningJobId: string, options?: Core.RequestOptions): Core.APIPromise { - return this._client.post(`/fine_tuning/jobs/${fineTuningJobId}/cancel`, options); + cancel(fineTuningJobID: string, options?: RequestOptions): APIPromise { + return this._client.post(path`/fine_tuning/jobs/${fineTuningJobID}/cancel`, options); } /** * Get status updates for a fine-tuning job. */ listEvents( - fineTuningJobId: string, - query?: JobListEventsParams, - options?: Core.RequestOptions, - ): Core.PagePromise; - listEvents( - fineTuningJobId: string, - options?: Core.RequestOptions, - ): Core.PagePromise; - listEvents( - fineTuningJobId: string, - query: JobListEventsParams | Core.RequestOptions = {}, - options?: Core.RequestOptions, - ): Core.PagePromise { - if (isRequestOptions(query)) { - return this.listEvents(fineTuningJobId, {}, query); - } - return this._client.getAPIList(`/fine_tuning/jobs/${fineTuningJobId}/events`, FineTuningJobEventsPage, { - query, - ...options, - }); + fineTuningJobID: string, + query: JobListEventsParams | null | undefined = {}, + options?: RequestOptions, + ): PagePromise { + return this._client.getAPIList( + path`/fine_tuning/jobs/${fineTuningJobID}/events`, + CursorPage, + { query, ...options }, + ); } } -export class FineTuningJobsPage extends CursorPage {} +export type FineTuningJobsPage = CursorPage; -export class FineTuningJobEventsPage extends CursorPage {} +export type FineTuningJobEventsPage = CursorPage; /** * The `fine_tuning.job` object represents a fine-tuning job that has been created @@ -516,7 +498,7 @@ export interface JobCreateParams { export namespace JobCreateParams { /** - * @deprecated: The hyperparameters used for the fine-tuning job. This value is now + * @deprecated The hyperparameters used for the fine-tuning job. This value is now * deprecated in favor of `method`, and should be passed in under the `method` * parameter. */ @@ -694,10 +676,7 @@ export interface JobListParams extends CursorPageParams {} export interface JobListEventsParams extends CursorPageParams {} -Jobs.FineTuningJobsPage = FineTuningJobsPage; -Jobs.FineTuningJobEventsPage = FineTuningJobEventsPage; Jobs.Checkpoints = Checkpoints; -Jobs.FineTuningJobCheckpointsPage = FineTuningJobCheckpointsPage; export declare namespace Jobs { export { @@ -706,8 +685,8 @@ export declare namespace Jobs { type FineTuningJobIntegration as FineTuningJobIntegration, type FineTuningJobWandbIntegration as FineTuningJobWandbIntegration, type FineTuningJobWandbIntegrationObject as FineTuningJobWandbIntegrationObject, - FineTuningJobsPage as FineTuningJobsPage, - FineTuningJobEventsPage as FineTuningJobEventsPage, + type FineTuningJobsPage as FineTuningJobsPage, + type FineTuningJobEventsPage as FineTuningJobEventsPage, type JobCreateParams as JobCreateParams, type JobListParams as JobListParams, type JobListEventsParams as JobListEventsParams, @@ -716,7 +695,7 @@ export declare namespace Jobs { export { Checkpoints as Checkpoints, type FineTuningJobCheckpoint as FineTuningJobCheckpoint, - FineTuningJobCheckpointsPage as FineTuningJobCheckpointsPage, + type FineTuningJobCheckpointsPage as FineTuningJobCheckpointsPage, type CheckpointListParams as CheckpointListParams, }; } diff --git a/src/resources/images.ts b/src/resources/images.ts index 8e1c6d92e..d8eb5be4c 100644 --- a/src/resources/images.ts +++ b/src/resources/images.ts @@ -1,30 +1,36 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import { APIResource } from '../resource'; -import * as Core from '../core'; +import { APIPromise } from '../api-promise'; +import { type Uploadable } from '../uploads'; +import { RequestOptions } from '../internal/request-options'; +import { multipartFormRequestOptions } from '../internal/uploads'; export class Images extends APIResource { /** * Creates a variation of a given image. */ - createVariation( - body: ImageCreateVariationParams, - options?: Core.RequestOptions, - ): Core.APIPromise { - return this._client.post('/images/variations', Core.multipartFormRequestOptions({ body, ...options })); + createVariation(body: ImageCreateVariationParams, options?: RequestOptions): APIPromise { + return this._client.post( + '/images/variations', + multipartFormRequestOptions({ body, ...options }, this._client), + ); } /** * Creates an edited or extended image given an original image and a prompt. */ - edit(body: ImageEditParams, options?: Core.RequestOptions): Core.APIPromise { - return this._client.post('/images/edits', Core.multipartFormRequestOptions({ body, ...options })); + edit(body: ImageEditParams, options?: RequestOptions): APIPromise { + return this._client.post( + '/images/edits', + multipartFormRequestOptions({ body, ...options }, this._client), + ); } /** * Creates an image given a prompt. */ - generate(body: ImageGenerateParams, options?: Core.RequestOptions): Core.APIPromise { + generate(body: ImageGenerateParams, options?: RequestOptions): APIPromise { return this._client.post('/images/generations', { body, ...options }); } } @@ -64,7 +70,7 @@ export interface ImageCreateVariationParams { * The image to use as the basis for the variation(s). Must be a valid PNG file, * less than 4MB, and square. */ - image: Core.Uploadable; + image: Uploadable; /** * The model to use for image generation. Only `dall-e-2` is supported at this @@ -104,7 +110,7 @@ export interface ImageEditParams { * The image to edit. Must be a valid PNG file, less than 4MB, and square. If mask * is not provided, image must have transparency, which will be used as the mask. */ - image: Core.Uploadable; + image: Uploadable; /** * A text description of the desired image(s). The maximum length is 1000 @@ -117,7 +123,7 @@ export interface ImageEditParams { * indicate where `image` should be edited. Must be a valid PNG file, less than * 4MB, and have the same dimensions as `image`. */ - mask?: Core.Uploadable; + mask?: Uploadable; /** * The model to use for image generation. Only `dall-e-2` is supported at this diff --git a/src/resources/index.ts b/src/resources/index.ts index ad0302357..c1d06d8ce 100644 --- a/src/resources/index.ts +++ b/src/resources/index.ts @@ -4,13 +4,13 @@ export * from './chat/index'; export * from './shared'; export { Audio, type AudioModel, type AudioResponseFormat } from './audio/audio'; export { - BatchesPage, Batches, type Batch, type BatchError, type BatchRequestCounts, type BatchCreateParams, type BatchListParams, + type BatchesPage, } from './batches'; export { Beta } from './beta/beta'; export { @@ -30,7 +30,6 @@ export { type EmbeddingCreateParams, } from './embeddings'; export { - FileObjectsPage, Files, type FileContent, type FileDeleted, @@ -38,6 +37,7 @@ export { type FilePurpose, type FileCreateParams, type FileListParams, + type FileObjectsPage, } from './files'; export { FineTuning } from './fine-tuning/fine-tuning'; export { @@ -49,7 +49,7 @@ export { type ImageEditParams, type ImageGenerateParams, } from './images'; -export { ModelsPage, Models, type Model, type ModelDeleted } from './models'; +export { Models, type Model, type ModelDeleted, type ModelsPage } from './models'; export { Moderations, type Moderation, diff --git a/src/resources/models.ts b/src/resources/models.ts index 6d8cd5296..69ba58279 100644 --- a/src/resources/models.ts +++ b/src/resources/models.ts @@ -1,39 +1,39 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import { APIResource } from '../resource'; -import * as Core from '../core'; -import { Page } from '../pagination'; +import { APIPromise } from '../api-promise'; +import { Page, PagePromise } from '../pagination'; +import { RequestOptions } from '../internal/request-options'; +import { path } from '../internal/utils/path'; export class Models extends APIResource { /** * Retrieves a model instance, providing basic information about the model such as * the owner and permissioning. */ - retrieve(model: string, options?: Core.RequestOptions): Core.APIPromise { - return this._client.get(`/models/${model}`, options); + retrieve(model: string, options?: RequestOptions): APIPromise { + return this._client.get(path`/models/${model}`, options); } /** * Lists the currently available models, and provides basic information about each * one such as the owner and availability. */ - list(options?: Core.RequestOptions): Core.PagePromise { - return this._client.getAPIList('/models', ModelsPage, options); + list(options?: RequestOptions): PagePromise { + return this._client.getAPIList('/models', Page, options); } /** * Delete a fine-tuned model. You must have the Owner role in your organization to * delete a model. */ - del(model: string, options?: Core.RequestOptions): Core.APIPromise { - return this._client.delete(`/models/${model}`, options); + delete(model: string, options?: RequestOptions): APIPromise { + return this._client.delete(path`/models/${model}`, options); } } -/** - * Note: no pagination actually occurs yet, this is for forwards-compatibility. - */ -export class ModelsPage extends Page {} +// Note: no pagination actually occurs yet, this is for forwards-compatibility. +export type ModelsPage = Page; /** * Describes an OpenAI model offering that can be used with the API. @@ -68,8 +68,6 @@ export interface ModelDeleted { object: string; } -Models.ModelsPage = ModelsPage; - export declare namespace Models { - export { type Model as Model, type ModelDeleted as ModelDeleted, ModelsPage as ModelsPage }; + export { type Model as Model, type ModelDeleted as ModelDeleted, type ModelsPage as ModelsPage }; } diff --git a/src/resources/moderations.ts b/src/resources/moderations.ts index f7b16166d..478850e5e 100644 --- a/src/resources/moderations.ts +++ b/src/resources/moderations.ts @@ -1,17 +1,15 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import { APIResource } from '../resource'; -import * as Core from '../core'; +import { APIPromise } from '../api-promise'; +import { RequestOptions } from '../internal/request-options'; export class Moderations extends APIResource { /** * Classifies if text and/or image inputs are potentially harmful. Learn more in * the [moderation guide](https://platform.openai.com/docs/guides/moderation). */ - create( - body: ModerationCreateParams, - options?: Core.RequestOptions, - ): Core.APIPromise { + create(body: ModerationCreateParams, options?: RequestOptions): APIPromise { return this._client.post('/moderations', { body, ...options }); } } @@ -75,14 +73,14 @@ export namespace Moderation { * execution of wrongdoing, or that gives advice or instruction on how to commit * illicit acts. For example, "how to shoplift" would fit this category. */ - illicit: boolean; + illicit: boolean | null; /** * Content that includes instructions or advice that facilitate the planning or * execution of wrongdoing that also includes violence, or that gives advice or * instruction on the procurement of any weapon. */ - 'illicit/violent': boolean; + 'illicit/violent': boolean | null; /** * Content that promotes, encourages, or depicts acts of self-harm, such as diff --git a/src/resources/shared.ts b/src/resources/shared.ts index f44fda8a7..3bb11582f 100644 --- a/src/resources/shared.ts +++ b/src/resources/shared.ts @@ -55,6 +55,16 @@ export interface FunctionDefinition { */ export type FunctionParameters = Record; +/** + * Set of 16 key-value pairs that can be attached to an object. This can be useful + * for storing additional information about the object in a structured format, and + * querying for objects via API or the dashboard. + * + * Keys are strings with a maximum length of 64 characters. Values are strings with + * a maximum length of 512 characters. + */ +export type Metadata = Record; + export interface ResponseFormatJSONObject { /** * The type of response format being defined: `json_object` diff --git a/src/resources/uploads/parts.ts b/src/resources/uploads/parts.ts index 9b54c99e6..18568c3e4 100644 --- a/src/resources/uploads/parts.ts +++ b/src/resources/uploads/parts.ts @@ -1,7 +1,11 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import { APIResource } from '../../resource'; -import * as Core from '../../core'; +import { APIPromise } from '../../api-promise'; +import { type Uploadable } from '../../uploads'; +import { RequestOptions } from '../../internal/request-options'; +import { multipartFormRequestOptions } from '../../internal/uploads'; +import { path } from '../../internal/utils/path'; export class Parts extends APIResource { /** @@ -17,14 +21,10 @@ export class Parts extends APIResource { * order of the Parts when you * [complete the Upload](https://platform.openai.com/docs/api-reference/uploads/complete). */ - create( - uploadId: string, - body: PartCreateParams, - options?: Core.RequestOptions, - ): Core.APIPromise { + create(uploadID: string, body: PartCreateParams, options?: RequestOptions): APIPromise { return this._client.post( - `/uploads/${uploadId}/parts`, - Core.multipartFormRequestOptions({ body, ...options }), + path`/uploads/${uploadID}/parts`, + multipartFormRequestOptions({ body, ...options }, this._client), ); } } @@ -58,7 +58,7 @@ export interface PartCreateParams { /** * The chunk of bytes for this Part. */ - data: Core.Uploadable; + data: Uploadable; } export declare namespace Parts { diff --git a/src/resources/uploads/uploads.ts b/src/resources/uploads/uploads.ts index 8491d0fe2..a2f1b5250 100644 --- a/src/resources/uploads/uploads.ts +++ b/src/resources/uploads/uploads.ts @@ -1,10 +1,12 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import { APIResource } from '../../resource'; -import * as Core from '../../core'; import * as FilesAPI from '../files'; import * as PartsAPI from './parts'; import { PartCreateParams, Parts, UploadPart } from './parts'; +import { APIPromise } from '../../api-promise'; +import { RequestOptions } from '../../internal/request-options'; +import { path } from '../../internal/utils/path'; export class Uploads extends APIResource { parts: PartsAPI.Parts = new PartsAPI.Parts(this._client); @@ -31,15 +33,15 @@ export class Uploads extends APIResource { * the documentation on * [creating a File](https://platform.openai.com/docs/api-reference/files/create). */ - create(body: UploadCreateParams, options?: Core.RequestOptions): Core.APIPromise { + create(body: UploadCreateParams, options?: RequestOptions): APIPromise { return this._client.post('/uploads', { body, ...options }); } /** * Cancels the Upload. No Parts may be added after an Upload is cancelled. */ - cancel(uploadId: string, options?: Core.RequestOptions): Core.APIPromise { - return this._client.post(`/uploads/${uploadId}/cancel`, options); + cancel(uploadID: string, options?: RequestOptions): APIPromise { + return this._client.post(path`/uploads/${uploadID}/cancel`, options); } /** @@ -57,12 +59,8 @@ export class Uploads extends APIResource { * initially specified when creating the Upload object. No Parts may be added after * an Upload is completed. */ - complete( - uploadId: string, - body: UploadCompleteParams, - options?: Core.RequestOptions, - ): Core.APIPromise { - return this._client.post(`/uploads/${uploadId}/complete`, { body, ...options }); + complete(uploadID: string, body: UploadCompleteParams, options?: RequestOptions): APIPromise { + return this._client.post(path`/uploads/${uploadID}/complete`, { body, ...options }); } } @@ -86,7 +84,7 @@ export interface Upload { created_at: number; /** - * The Unix timestamp (in seconds) for when the Upload was created. + * The Unix timestamp (in seconds) for when the Upload will expire. */ expires_at: number; @@ -113,7 +111,7 @@ export interface Upload { status: 'pending' | 'completed' | 'cancelled' | 'expired'; /** - * The ready File object after the Upload is completed. + * The `File` object represents a document that has been uploaded to OpenAI. */ file?: FilesAPI.FileObject | null; } diff --git a/src/shims/node.ts b/src/shims/node.ts deleted file mode 100644 index 73df5600c..000000000 --- a/src/shims/node.ts +++ /dev/null @@ -1,50 +0,0 @@ -// @ts-ignore -import * as types from '../_shims/node-types'; -import { setShims } from '../_shims/registry'; -import { getRuntime } from '../_shims/node-runtime'; -setShims(getRuntime()); - -declare module '../_shims/manual-types' { - export namespace manual { - // @ts-ignore - export type Agent = types.Agent; - // @ts-ignore - export import fetch = types.fetch; - // @ts-ignore - export type Request = types.Request; - // @ts-ignore - export type RequestInfo = types.RequestInfo; - // @ts-ignore - export type RequestInit = types.RequestInit; - // @ts-ignore - export type Response = types.Response; - // @ts-ignore - export type ResponseInit = types.ResponseInit; - // @ts-ignore - export type ResponseType = types.ResponseType; - // @ts-ignore - export type BodyInit = types.BodyInit; - // @ts-ignore - export type Headers = types.Headers; - // @ts-ignore - export type HeadersInit = types.HeadersInit; - // @ts-ignore - export type BlobPropertyBag = types.BlobPropertyBag; - // @ts-ignore - export type FilePropertyBag = types.FilePropertyBag; - // @ts-ignore - export type FileFromPathOptions = types.FileFromPathOptions; - // @ts-ignore - export import FormData = types.FormData; - // @ts-ignore - export import File = types.File; - // @ts-ignore - export import Blob = types.Blob; - // @ts-ignore - export type Readable = types.Readable; - // @ts-ignore - export type FsReadStream = types.FsReadStream; - // @ts-ignore - export import ReadableStream = types.ReadableStream; - } -} diff --git a/src/shims/web.ts b/src/shims/web.ts deleted file mode 100644 index f72d78444..000000000 --- a/src/shims/web.ts +++ /dev/null @@ -1,50 +0,0 @@ -// @ts-ignore -import * as types from '../_shims/web-types'; -import { setShims } from '../_shims/registry'; -import { getRuntime } from '../_shims/web-runtime'; -setShims(getRuntime({ manuallyImported: true })); - -declare module '../_shims/manual-types' { - export namespace manual { - // @ts-ignore - export type Agent = types.Agent; - // @ts-ignore - export import fetch = types.fetch; - // @ts-ignore - export type Request = types.Request; - // @ts-ignore - export type RequestInfo = types.RequestInfo; - // @ts-ignore - export type RequestInit = types.RequestInit; - // @ts-ignore - export type Response = types.Response; - // @ts-ignore - export type ResponseInit = types.ResponseInit; - // @ts-ignore - export type ResponseType = types.ResponseType; - // @ts-ignore - export type BodyInit = types.BodyInit; - // @ts-ignore - export type Headers = types.Headers; - // @ts-ignore - export type HeadersInit = types.HeadersInit; - // @ts-ignore - export type BlobPropertyBag = types.BlobPropertyBag; - // @ts-ignore - export type FilePropertyBag = types.FilePropertyBag; - // @ts-ignore - export type FileFromPathOptions = types.FileFromPathOptions; - // @ts-ignore - export import FormData = types.FormData; - // @ts-ignore - export import File = types.File; - // @ts-ignore - export import Blob = types.Blob; - // @ts-ignore - export type Readable = types.Readable; - // @ts-ignore - export type FsReadStream = types.FsReadStream; - // @ts-ignore - export import ReadableStream = types.ReadableStream; - } -} diff --git a/src/streaming.ts b/src/streaming.ts index 2891e6ac3..47c366071 100644 --- a/src/streaming.ts +++ b/src/streaming.ts @@ -1,10 +1,13 @@ -import { ReadableStream, type Response } from './_shims/index'; import { OpenAIError } from './error'; -import { LineDecoder } from './internal/decoders/line'; +import { type ReadableStream } from './internal/shim-types'; +import { makeReadableStream } from './internal/shims'; +import { findDoubleNewlineIndex, LineDecoder } from './internal/decoders/line'; +import { ReadableStreamToAsyncIterable } from './internal/shims'; +import { isAbortError } from './internal/errors'; import { APIError } from './error'; -type Bytes = string | ArrayBuffer | Uint8Array | Buffer | null | undefined; +type Bytes = string | ArrayBuffer | Uint8Array | null | undefined; export type ServerSentEvent = { event: string | null; @@ -75,7 +78,7 @@ export class Stream implements AsyncIterable { done = true; } catch (e) { // If the user calls `stream.controller.abort()`, we should exit without throwing. - if (e instanceof Error && e.name === 'AbortError') return; + if (isAbortError(e)) return; throw e; } finally { // If the user `break`s, abort the ongoing request. @@ -96,7 +99,7 @@ export class Stream implements AsyncIterable { async function* iterLines(): AsyncGenerator { const lineDecoder = new LineDecoder(); - const iter = readableStreamAsyncIterable(readableStream); + const iter = ReadableStreamToAsyncIterable(readableStream); for await (const chunk of iter) { for (const line of lineDecoder.decode(chunk)) { yield line; @@ -122,7 +125,7 @@ export class Stream implements AsyncIterable { done = true; } catch (e) { // If the user calls `stream.controller.abort()`, we should exit without throwing. - if (e instanceof Error && e.name === 'AbortError') return; + if (isAbortError(e)) return; throw e; } finally { // If the user `break`s, abort the ongoing request. @@ -173,9 +176,11 @@ export class Stream implements AsyncIterable { toReadableStream(): ReadableStream { const self = this; let iter: AsyncIterator; - const encoder = new TextEncoder(); + const encoder: { + encode(str: string): Uint8Array; + } = new (globalThis as any).TextEncoder(); - return new ReadableStream({ + return makeReadableStream({ async start() { iter = self[Symbol.asyncIterator](); }, @@ -204,13 +209,21 @@ export async function* _iterSSEMessages( ): AsyncGenerator { if (!response.body) { controller.abort(); + if ( + typeof (globalThis as any).navigator !== 'undefined' && + (globalThis as any).navigator.product === 'ReactNative' + ) { + throw new OpenAIError( + `The default react-native fetch implementation does not support streaming. Please use expo/fetch: https://docs.expo.dev/versions/latest/sdk/expo/#expofetch-api`, + ); + } throw new OpenAIError(`Attempted to iterate over a response with no body`); } const sseDecoder = new SSEDecoder(); const lineDecoder = new LineDecoder(); - const iter = readableStreamAsyncIterable(response.body); + const iter = ReadableStreamToAsyncIterable(response.body); for await (const sseChunk of iterSSEChunks(iter)) { for (const line of lineDecoder.decode(sseChunk)) { const sse = sseDecoder.decode(line); @@ -238,7 +251,7 @@ async function* iterSSEChunks(iterator: AsyncIterableIterator): AsyncGene const binaryChunk = chunk instanceof ArrayBuffer ? new Uint8Array(chunk) - : typeof chunk === 'string' ? new TextEncoder().encode(chunk) + : typeof chunk === 'string' ? new (globalThis as any).TextEncoder().encode(chunk) : chunk; let newData = new Uint8Array(data.length + binaryChunk.length); @@ -258,37 +271,6 @@ async function* iterSSEChunks(iterator: AsyncIterableIterator): AsyncGene } } -function findDoubleNewlineIndex(buffer: Uint8Array): number { - // This function searches the buffer for the end patterns (\r\r, \n\n, \r\n\r\n) - // and returns the index right after the first occurrence of any pattern, - // or -1 if none of the patterns are found. - const newline = 0x0a; // \n - const carriage = 0x0d; // \r - - for (let i = 0; i < buffer.length - 2; i++) { - if (buffer[i] === newline && buffer[i + 1] === newline) { - // \n\n - return i + 2; - } - if (buffer[i] === carriage && buffer[i + 1] === carriage) { - // \r\r - return i + 2; - } - if ( - buffer[i] === carriage && - buffer[i + 1] === newline && - i + 3 < buffer.length && - buffer[i + 2] === carriage && - buffer[i + 3] === newline - ) { - // \r\n\r\n - return i + 4; - } - } - - return -1; -} - class SSEDecoder { private data: string[]; private event: string | null; @@ -344,17 +326,6 @@ class SSEDecoder { } } -/** This is an internal helper function that's just used for testing */ -export function _decodeChunks(chunks: string[]): string[] { - const decoder = new LineDecoder(); - const lines: string[] = []; - for (const chunk of chunks) { - lines.push(...decoder.decode(chunk)); - } - - return lines; -} - function partition(str: string, delimiter: string): [string, string, string] { const index = str.indexOf(delimiter); if (index !== -1) { @@ -363,36 +334,3 @@ function partition(str: string, delimiter: string): [string, string, string] { return [str, '', '']; } - -/** - * Most browsers don't yet have async iterable support for ReadableStream, - * and Node has a very different way of reading bytes from its "ReadableStream". - * - * This polyfill was pulled from https://github.com/MattiasBuelens/web-streams-polyfill/pull/122#issuecomment-1627354490 - */ -export function readableStreamAsyncIterable(stream: any): AsyncIterableIterator { - if (stream[Symbol.asyncIterator]) return stream; - - const reader = stream.getReader(); - return { - async next() { - try { - const result = await reader.read(); - if (result?.done) reader.releaseLock(); // release lock when stream becomes closed - return result; - } catch (e) { - reader.releaseLock(); // release lock when stream becomes errored - throw e; - } - }, - async return() { - const cancelPromise = reader.cancel(); - reader.releaseLock(); - await cancelPromise; - return { done: true, value: undefined }; - }, - [Symbol.asyncIterator]() { - return this; - }, - }; -} diff --git a/src/uploads.ts b/src/uploads.ts index 8fd2154d4..79d3073ea 100644 --- a/src/uploads.ts +++ b/src/uploads.ts @@ -1,255 +1,2 @@ -import { type RequestOptions } from './core'; -import { - FormData, - File, - type Blob, - type FilePropertyBag, - getMultipartRequestOptions, - type FsReadStream, - isFsReadStream, -} from './_shims/index'; -import { MultipartBody } from './_shims/MultipartBody'; -export { fileFromPath } from './_shims/index'; - -type BlobLikePart = string | ArrayBuffer | ArrayBufferView | BlobLike | Uint8Array | DataView; -export type BlobPart = string | ArrayBuffer | ArrayBufferView | Blob | Uint8Array | DataView; - -/** - * Typically, this is a native "File" class. - * - * We provide the {@link toFile} utility to convert a variety of objects - * into the File class. - * - * For convenience, you can also pass a fetch Response, or in Node, - * the result of fs.createReadStream(). - */ -export type Uploadable = FileLike | ResponseLike | FsReadStream; - -/** - * Intended to match web.Blob, node.Blob, node-fetch.Blob, etc. - */ -export interface BlobLike { - /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Blob/size) */ - readonly size: number; - /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Blob/type) */ - readonly type: string; - /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Blob/text) */ - text(): Promise; - /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Blob/slice) */ - slice(start?: number, end?: number): BlobLike; - // unfortunately @types/node-fetch@^2.6.4 doesn't type the arrayBuffer method -} - -/** - * Intended to match web.File, node.File, node-fetch.File, etc. - */ -export interface FileLike extends BlobLike { - /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/File/lastModified) */ - readonly lastModified: number; - /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/File/name) */ - readonly name: string; -} - -/** - * Intended to match web.Response, node.Response, node-fetch.Response, etc. - */ -export interface ResponseLike { - url: string; - blob(): Promise; -} - -export const isResponseLike = (value: any): value is ResponseLike => - value != null && - typeof value === 'object' && - typeof value.url === 'string' && - typeof value.blob === 'function'; - -export const isFileLike = (value: any): value is FileLike => - value != null && - typeof value === 'object' && - typeof value.name === 'string' && - typeof value.lastModified === 'number' && - isBlobLike(value); - -/** - * The BlobLike type omits arrayBuffer() because @types/node-fetch@^2.6.4 lacks it; but this check - * adds the arrayBuffer() method type because it is available and used at runtime - */ -export const isBlobLike = (value: any): value is BlobLike & { arrayBuffer(): Promise } => - value != null && - typeof value === 'object' && - typeof value.size === 'number' && - typeof value.type === 'string' && - typeof value.text === 'function' && - typeof value.slice === 'function' && - typeof value.arrayBuffer === 'function'; - -export const isUploadable = (value: any): value is Uploadable => { - return isFileLike(value) || isResponseLike(value) || isFsReadStream(value); -}; - -export type ToFileInput = Uploadable | Exclude | AsyncIterable; - -/** - * Helper for creating a {@link File} to pass to an SDK upload method from a variety of different data formats - * @param value the raw content of the file. Can be an {@link Uploadable}, {@link BlobLikePart}, or {@link AsyncIterable} of {@link BlobLikePart}s - * @param {string=} name the name of the file. If omitted, toFile will try to determine a file name from bits if possible - * @param {Object=} options additional properties - * @param {string=} options.type the MIME type of the content - * @param {number=} options.lastModified the last modified timestamp - * @returns a {@link File} with the given properties - */ -export async function toFile( - value: ToFileInput | PromiseLike, - name?: string | null | undefined, - options?: FilePropertyBag | undefined, -): Promise { - // If it's a promise, resolve it. - value = await value; - - // If we've been given a `File` we don't need to do anything - if (isFileLike(value)) { - return value; - } - - if (isResponseLike(value)) { - const blob = await value.blob(); - name ||= new URL(value.url).pathname.split(/[\\/]/).pop() ?? 'unknown_file'; - - // we need to convert the `Blob` into an array buffer because the `Blob` class - // that `node-fetch` defines is incompatible with the web standard which results - // in `new File` interpreting it as a string instead of binary data. - const data = isBlobLike(blob) ? [(await blob.arrayBuffer()) as any] : [blob]; - - return new File(data, name, options); - } - - const bits = await getBytes(value); - - name ||= getName(value) ?? 'unknown_file'; - - if (!options?.type) { - const type = (bits[0] as any)?.type; - if (typeof type === 'string') { - options = { ...options, type }; - } - } - - return new File(bits, name, options); -} - -async function getBytes(value: ToFileInput): Promise> { - let parts: Array = []; - if ( - typeof value === 'string' || - ArrayBuffer.isView(value) || // includes Uint8Array, Buffer, etc. - value instanceof ArrayBuffer - ) { - parts.push(value); - } else if (isBlobLike(value)) { - parts.push(await value.arrayBuffer()); - } else if ( - isAsyncIterableIterator(value) // includes Readable, ReadableStream, etc. - ) { - for await (const chunk of value) { - parts.push(chunk as BlobPart); // TODO, consider validating? - } - } else { - throw new Error( - `Unexpected data type: ${typeof value}; constructor: ${value?.constructor - ?.name}; props: ${propsForError(value)}`, - ); - } - - return parts; -} - -function propsForError(value: any): string { - const props = Object.getOwnPropertyNames(value); - return `[${props.map((p) => `"${p}"`).join(', ')}]`; -} - -function getName(value: any): string | undefined { - return ( - getStringFromMaybeBuffer(value.name) || - getStringFromMaybeBuffer(value.filename) || - // For fs.ReadStream - getStringFromMaybeBuffer(value.path)?.split(/[\\/]/).pop() - ); -} - -const getStringFromMaybeBuffer = (x: string | Buffer | unknown): string | undefined => { - if (typeof x === 'string') return x; - if (typeof Buffer !== 'undefined' && x instanceof Buffer) return String(x); - return undefined; -}; - -const isAsyncIterableIterator = (value: any): value is AsyncIterableIterator => - value != null && typeof value === 'object' && typeof value[Symbol.asyncIterator] === 'function'; - -export const isMultipartBody = (body: any): body is MultipartBody => - body && typeof body === 'object' && body.body && body[Symbol.toStringTag] === 'MultipartBody'; - -/** - * Returns a multipart/form-data request if any part of the given request body contains a File / Blob value. - * Otherwise returns the request as is. - */ -export const maybeMultipartFormRequestOptions = async >( - opts: RequestOptions, -): Promise> => { - if (!hasUploadableValue(opts.body)) return opts; - - const form = await createForm(opts.body); - return getMultipartRequestOptions(form, opts); -}; - -export const multipartFormRequestOptions = async >( - opts: RequestOptions, -): Promise> => { - const form = await createForm(opts.body); - return getMultipartRequestOptions(form, opts); -}; - -export const createForm = async >(body: T | undefined): Promise => { - const form = new FormData(); - await Promise.all(Object.entries(body || {}).map(([key, value]) => addFormValue(form, key, value))); - return form; -}; - -const hasUploadableValue = (value: unknown): boolean => { - if (isUploadable(value)) return true; - if (Array.isArray(value)) return value.some(hasUploadableValue); - if (value && typeof value === 'object') { - for (const k in value) { - if (hasUploadableValue((value as any)[k])) return true; - } - } - return false; -}; - -const addFormValue = async (form: FormData, key: string, value: unknown): Promise => { - if (value === undefined) return; - if (value == null) { - throw new TypeError( - `Received null for "${key}"; to pass null in FormData, you must use the string 'null'`, - ); - } - - // TODO: make nested formats configurable - if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') { - form.append(key, String(value)); - } else if (isUploadable(value)) { - const file = await toFile(value); - form.append(key, file as File); - } else if (Array.isArray(value)) { - await Promise.all(value.map((entry) => addFormValue(form, key + '[]', entry))); - } else if (typeof value === 'object') { - await Promise.all( - Object.entries(value).map(([name, prop]) => addFormValue(form, `${key}[${name}]`, prop)), - ); - } else { - throw new TypeError( - `Invalid value given to form, expected a string, number, boolean, object, Array, File or Blob but got ${value} instead`, - ); - } -}; +export { type Uploadable } from './internal/uploads'; +export { toFile, type ToFileInput } from './internal/to-file'; diff --git a/src/version.ts b/src/version.ts index fdf4e5224..58d8f3c50 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1 +1 @@ -export const VERSION = '4.77.0'; // x-release-please-version +export const VERSION = '5.0.0-beta.0'; // x-release-please-version diff --git a/tests/api-resources/audio/transcriptions.test.ts b/tests/api-resources/audio/transcriptions.test.ts index 86ef5e576..6e5d560d0 100644 --- a/tests/api-resources/audio/transcriptions.test.ts +++ b/tests/api-resources/audio/transcriptions.test.ts @@ -1,7 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import OpenAI, { toFile } from 'openai'; -import { Response } from 'node-fetch'; const client = new OpenAI({ apiKey: 'My API Key', diff --git a/tests/api-resources/audio/translations.test.ts b/tests/api-resources/audio/translations.test.ts index 7966ff49a..940e4f38e 100644 --- a/tests/api-resources/audio/translations.test.ts +++ b/tests/api-resources/audio/translations.test.ts @@ -1,7 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import OpenAI, { toFile } from 'openai'; -import { Response } from 'node-fetch'; const client = new OpenAI({ apiKey: 'My API Key', diff --git a/tests/api-resources/batches.test.ts b/tests/api-resources/batches.test.ts index 96e200fb9..870fbec9d 100644 --- a/tests/api-resources/batches.test.ts +++ b/tests/api-resources/batches.test.ts @@ -1,7 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import OpenAI from 'openai'; -import { Response } from 'node-fetch'; const client = new OpenAI({ apiKey: 'My API Key', @@ -44,13 +43,6 @@ describe('resource batches', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - test('retrieve: request options instead of params are passed correctly', async () => { - // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error - await expect(client.batches.retrieve('batch_id', { path: '/_stainless_unknown_path' })).rejects.toThrow( - OpenAI.NotFoundError, - ); - }); - test('list', async () => { const responsePromise = client.batches.list(); const rawResponse = await responsePromise.asResponse(); @@ -62,13 +54,6 @@ describe('resource batches', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - test('list: request options instead of params are passed correctly', async () => { - // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error - await expect(client.batches.list({ path: '/_stainless_unknown_path' })).rejects.toThrow( - OpenAI.NotFoundError, - ); - }); - test('list: request options and params are passed correctly', async () => { // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error await expect( @@ -86,11 +71,4 @@ describe('resource batches', () => { expect(dataAndResponse.data).toBe(response); expect(dataAndResponse.response).toBe(rawResponse); }); - - test('cancel: request options instead of params are passed correctly', async () => { - // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error - await expect(client.batches.cancel('batch_id', { path: '/_stainless_unknown_path' })).rejects.toThrow( - OpenAI.NotFoundError, - ); - }); }); diff --git a/tests/api-resources/beta/assistants.test.ts b/tests/api-resources/beta/assistants.test.ts index a64465c77..8bdbc408e 100644 --- a/tests/api-resources/beta/assistants.test.ts +++ b/tests/api-resources/beta/assistants.test.ts @@ -1,7 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import OpenAI from 'openai'; -import { Response } from 'node-fetch'; const client = new OpenAI({ apiKey: 'My API Key', @@ -25,15 +24,18 @@ describe('resource assistants', () => { model: 'gpt-4o', description: 'description', instructions: 'instructions', - metadata: {}, + metadata: { foo: 'string' }, name: 'name', + reasoning_effort: 'low', response_format: 'auto', temperature: 1, tool_resources: { code_interpreter: { file_ids: ['string'] }, file_search: { vector_store_ids: ['string'], - vector_stores: [{ chunking_strategy: { type: 'auto' }, file_ids: ['string'], metadata: {} }], + vector_stores: [ + { chunking_strategy: { type: 'auto' }, file_ids: ['string'], metadata: { foo: 'string' } }, + ], }, }, tools: [{ type: 'code_interpreter' }], @@ -52,13 +54,6 @@ describe('resource assistants', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - test('retrieve: request options instead of params are passed correctly', async () => { - // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error - await expect( - client.beta.assistants.retrieve('assistant_id', { path: '/_stainless_unknown_path' }), - ).rejects.toThrow(OpenAI.NotFoundError); - }); - test('update', async () => { const responsePromise = client.beta.assistants.update('assistant_id', {}); const rawResponse = await responsePromise.asResponse(); @@ -81,13 +76,6 @@ describe('resource assistants', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - test('list: request options instead of params are passed correctly', async () => { - // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error - await expect(client.beta.assistants.list({ path: '/_stainless_unknown_path' })).rejects.toThrow( - OpenAI.NotFoundError, - ); - }); - test('list: request options and params are passed correctly', async () => { // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error await expect( @@ -98,8 +86,8 @@ describe('resource assistants', () => { ).rejects.toThrow(OpenAI.NotFoundError); }); - test('del', async () => { - const responsePromise = client.beta.assistants.del('assistant_id'); + test('delete', async () => { + const responsePromise = client.beta.assistants.delete('assistant_id'); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -108,11 +96,4 @@ describe('resource assistants', () => { expect(dataAndResponse.data).toBe(response); expect(dataAndResponse.response).toBe(rawResponse); }); - - test('del: request options instead of params are passed correctly', async () => { - // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error - await expect( - client.beta.assistants.del('assistant_id', { path: '/_stainless_unknown_path' }), - ).rejects.toThrow(OpenAI.NotFoundError); - }); }); diff --git a/tests/api-resources/beta/realtime/sessions.test.ts b/tests/api-resources/beta/realtime/sessions.test.ts new file mode 100644 index 000000000..1a75a532c --- /dev/null +++ b/tests/api-resources/beta/realtime/sessions.test.ts @@ -0,0 +1,21 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import OpenAI from 'openai'; + +const client = new OpenAI({ + apiKey: 'My API Key', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010/', +}); + +describe('resource sessions', () => { + test('create', async () => { + const responsePromise = client.beta.realtime.sessions.create({}); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); +}); diff --git a/tests/api-resources/beta/threads/messages.test.ts b/tests/api-resources/beta/threads/messages.test.ts index c1f5f7b6e..587daf0a1 100644 --- a/tests/api-resources/beta/threads/messages.test.ts +++ b/tests/api-resources/beta/threads/messages.test.ts @@ -1,7 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import OpenAI from 'openai'; -import { Response } from 'node-fetch'; const client = new OpenAI({ apiKey: 'My API Key', @@ -28,12 +27,12 @@ describe('resource messages', () => { content: 'string', role: 'user', attachments: [{ file_id: 'file_id', tools: [{ type: 'code_interpreter' }] }], - metadata: {}, + metadata: { foo: 'string' }, }); }); - test('retrieve', async () => { - const responsePromise = client.beta.threads.messages.retrieve('thread_id', 'message_id'); + test('retrieve: only required params', async () => { + const responsePromise = client.beta.threads.messages.retrieve('message_id', { thread_id: 'thread_id' }); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -43,15 +42,12 @@ describe('resource messages', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - test('retrieve: request options instead of params are passed correctly', async () => { - // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error - await expect( - client.beta.threads.messages.retrieve('thread_id', 'message_id', { path: '/_stainless_unknown_path' }), - ).rejects.toThrow(OpenAI.NotFoundError); + test('retrieve: required and optional params', async () => { + const response = await client.beta.threads.messages.retrieve('message_id', { thread_id: 'thread_id' }); }); - test('update', async () => { - const responsePromise = client.beta.threads.messages.update('thread_id', 'message_id', {}); + test('update: only required params', async () => { + const responsePromise = client.beta.threads.messages.update('message_id', { thread_id: 'thread_id' }); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -61,6 +57,13 @@ describe('resource messages', () => { expect(dataAndResponse.response).toBe(rawResponse); }); + test('update: required and optional params', async () => { + const response = await client.beta.threads.messages.update('message_id', { + thread_id: 'thread_id', + metadata: { foo: 'string' }, + }); + }); + test('list', async () => { const responsePromise = client.beta.threads.messages.list('thread_id'); const rawResponse = await responsePromise.asResponse(); @@ -72,13 +75,6 @@ describe('resource messages', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - test('list: request options instead of params are passed correctly', async () => { - // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error - await expect( - client.beta.threads.messages.list('thread_id', { path: '/_stainless_unknown_path' }), - ).rejects.toThrow(OpenAI.NotFoundError); - }); - test('list: request options and params are passed correctly', async () => { // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error await expect( @@ -90,8 +86,8 @@ describe('resource messages', () => { ).rejects.toThrow(OpenAI.NotFoundError); }); - test('del', async () => { - const responsePromise = client.beta.threads.messages.del('thread_id', 'message_id'); + test('delete: only required params', async () => { + const responsePromise = client.beta.threads.messages.delete('message_id', { thread_id: 'thread_id' }); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -101,10 +97,7 @@ describe('resource messages', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - test('del: request options instead of params are passed correctly', async () => { - // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error - await expect( - client.beta.threads.messages.del('thread_id', 'message_id', { path: '/_stainless_unknown_path' }), - ).rejects.toThrow(OpenAI.NotFoundError); + test('delete: required and optional params', async () => { + const response = await client.beta.threads.messages.delete('message_id', { thread_id: 'thread_id' }); }); }); diff --git a/tests/api-resources/beta/threads/runs/runs.test.ts b/tests/api-resources/beta/threads/runs/runs.test.ts index 4fd8261ac..118a4f324 100644 --- a/tests/api-resources/beta/threads/runs/runs.test.ts +++ b/tests/api-resources/beta/threads/runs/runs.test.ts @@ -1,7 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import OpenAI from 'openai'; -import { Response } from 'node-fetch'; const client = new OpenAI({ apiKey: 'My API Key', @@ -30,15 +29,16 @@ describe('resource runs', () => { content: 'string', role: 'user', attachments: [{ file_id: 'file_id', tools: [{ type: 'code_interpreter' }] }], - metadata: {}, + metadata: { foo: 'string' }, }, ], instructions: 'instructions', max_completion_tokens: 256, max_prompt_tokens: 256, - metadata: {}, + metadata: { foo: 'string' }, model: 'gpt-4o', parallel_tool_calls: true, + reasoning_effort: 'low', response_format: 'auto', stream: false, temperature: 1, @@ -49,8 +49,8 @@ describe('resource runs', () => { }); }); - test('retrieve', async () => { - const responsePromise = client.beta.threads.runs.retrieve('thread_id', 'run_id'); + test('retrieve: only required params', async () => { + const responsePromise = client.beta.threads.runs.retrieve('run_id', { thread_id: 'thread_id' }); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -60,15 +60,12 @@ describe('resource runs', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - test('retrieve: request options instead of params are passed correctly', async () => { - // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error - await expect( - client.beta.threads.runs.retrieve('thread_id', 'run_id', { path: '/_stainless_unknown_path' }), - ).rejects.toThrow(OpenAI.NotFoundError); + test('retrieve: required and optional params', async () => { + const response = await client.beta.threads.runs.retrieve('run_id', { thread_id: 'thread_id' }); }); - test('update', async () => { - const responsePromise = client.beta.threads.runs.update('thread_id', 'run_id', {}); + test('update: only required params', async () => { + const responsePromise = client.beta.threads.runs.update('run_id', { thread_id: 'thread_id' }); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -78,6 +75,13 @@ describe('resource runs', () => { expect(dataAndResponse.response).toBe(rawResponse); }); + test('update: required and optional params', async () => { + const response = await client.beta.threads.runs.update('run_id', { + thread_id: 'thread_id', + metadata: { foo: 'string' }, + }); + }); + test('list', async () => { const responsePromise = client.beta.threads.runs.list('thread_id'); const rawResponse = await responsePromise.asResponse(); @@ -89,13 +93,6 @@ describe('resource runs', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - test('list: request options instead of params are passed correctly', async () => { - // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error - await expect( - client.beta.threads.runs.list('thread_id', { path: '/_stainless_unknown_path' }), - ).rejects.toThrow(OpenAI.NotFoundError); - }); - test('list: request options and params are passed correctly', async () => { // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error await expect( @@ -107,8 +104,8 @@ describe('resource runs', () => { ).rejects.toThrow(OpenAI.NotFoundError); }); - test('cancel', async () => { - const responsePromise = client.beta.threads.runs.cancel('thread_id', 'run_id'); + test('cancel: only required params', async () => { + const responsePromise = client.beta.threads.runs.cancel('run_id', { thread_id: 'thread_id' }); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -118,15 +115,13 @@ describe('resource runs', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - test('cancel: request options instead of params are passed correctly', async () => { - // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error - await expect( - client.beta.threads.runs.cancel('thread_id', 'run_id', { path: '/_stainless_unknown_path' }), - ).rejects.toThrow(OpenAI.NotFoundError); + test('cancel: required and optional params', async () => { + const response = await client.beta.threads.runs.cancel('run_id', { thread_id: 'thread_id' }); }); test('submitToolOutputs: only required params', async () => { - const responsePromise = client.beta.threads.runs.submitToolOutputs('thread_id', 'run_id', { + const responsePromise = client.beta.threads.runs.submitToolOutputs('run_id', { + thread_id: 'thread_id', tool_outputs: [{}], }); const rawResponse = await responsePromise.asResponse(); @@ -139,7 +134,8 @@ describe('resource runs', () => { }); test('submitToolOutputs: required and optional params', async () => { - const response = await client.beta.threads.runs.submitToolOutputs('thread_id', 'run_id', { + const response = await client.beta.threads.runs.submitToolOutputs('run_id', { + thread_id: 'thread_id', tool_outputs: [{ output: 'output', tool_call_id: 'tool_call_id' }], stream: false, }); diff --git a/tests/api-resources/beta/threads/runs/steps.test.ts b/tests/api-resources/beta/threads/runs/steps.test.ts index 64cd228ae..cad671c5c 100644 --- a/tests/api-resources/beta/threads/runs/steps.test.ts +++ b/tests/api-resources/beta/threads/runs/steps.test.ts @@ -1,7 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import OpenAI from 'openai'; -import { Response } from 'node-fetch'; const client = new OpenAI({ apiKey: 'My API Key', @@ -9,8 +8,11 @@ const client = new OpenAI({ }); describe('resource steps', () => { - test('retrieve', async () => { - const responsePromise = client.beta.threads.runs.steps.retrieve('thread_id', 'run_id', 'step_id'); + test('retrieve: only required params', async () => { + const responsePromise = client.beta.threads.runs.steps.retrieve('step_id', { + thread_id: 'thread_id', + run_id: 'run_id', + }); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -20,30 +22,16 @@ describe('resource steps', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - test('retrieve: request options instead of params are passed correctly', async () => { - // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error - await expect( - client.beta.threads.runs.steps.retrieve('thread_id', 'run_id', 'step_id', { - path: '/_stainless_unknown_path', - }), - ).rejects.toThrow(OpenAI.NotFoundError); + test('retrieve: required and optional params', async () => { + const response = await client.beta.threads.runs.steps.retrieve('step_id', { + thread_id: 'thread_id', + run_id: 'run_id', + include: ['step_details.tool_calls[*].file_search.results[*].content'], + }); }); - test('retrieve: request options and params are passed correctly', async () => { - // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error - await expect( - client.beta.threads.runs.steps.retrieve( - 'thread_id', - 'run_id', - 'step_id', - { include: ['step_details.tool_calls[*].file_search.results[*].content'] }, - { path: '/_stainless_unknown_path' }, - ), - ).rejects.toThrow(OpenAI.NotFoundError); - }); - - test('list', async () => { - const responsePromise = client.beta.threads.runs.steps.list('thread_id', 'run_id'); + test('list: only required params', async () => { + const responsePromise = client.beta.threads.runs.steps.list('run_id', { thread_id: 'thread_id' }); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -53,28 +41,14 @@ describe('resource steps', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - test('list: request options instead of params are passed correctly', async () => { - // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error - await expect( - client.beta.threads.runs.steps.list('thread_id', 'run_id', { path: '/_stainless_unknown_path' }), - ).rejects.toThrow(OpenAI.NotFoundError); - }); - - test('list: request options and params are passed correctly', async () => { - // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error - await expect( - client.beta.threads.runs.steps.list( - 'thread_id', - 'run_id', - { - after: 'after', - before: 'before', - include: ['step_details.tool_calls[*].file_search.results[*].content'], - limit: 0, - order: 'asc', - }, - { path: '/_stainless_unknown_path' }, - ), - ).rejects.toThrow(OpenAI.NotFoundError); + test('list: required and optional params', async () => { + const response = await client.beta.threads.runs.steps.list('run_id', { + thread_id: 'thread_id', + after: 'after', + before: 'before', + include: ['step_details.tool_calls[*].file_search.results[*].content'], + limit: 0, + order: 'asc', + }); }); }); diff --git a/tests/api-resources/beta/threads/threads.test.ts b/tests/api-resources/beta/threads/threads.test.ts index aba266316..532bacb7c 100644 --- a/tests/api-resources/beta/threads/threads.test.ts +++ b/tests/api-resources/beta/threads/threads.test.ts @@ -1,7 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import OpenAI from 'openai'; -import { Response } from 'node-fetch'; const client = new OpenAI({ apiKey: 'My API Key', @@ -20,13 +19,6 @@ describe('resource threads', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - test('create: request options instead of params are passed correctly', async () => { - // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error - await expect(client.beta.threads.create({ path: '/_stainless_unknown_path' })).rejects.toThrow( - OpenAI.NotFoundError, - ); - }); - test('create: request options and params are passed correctly', async () => { // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error await expect( @@ -37,15 +29,17 @@ describe('resource threads', () => { content: 'string', role: 'user', attachments: [{ file_id: 'file_id', tools: [{ type: 'code_interpreter' }] }], - metadata: {}, + metadata: { foo: 'string' }, }, ], - metadata: {}, + metadata: { foo: 'string' }, tool_resources: { code_interpreter: { file_ids: ['string'] }, file_search: { vector_store_ids: ['string'], - vector_stores: [{ chunking_strategy: { type: 'auto' }, file_ids: ['string'], metadata: {} }], + vector_stores: [ + { chunking_strategy: { type: 'auto' }, file_ids: ['string'], metadata: { foo: 'string' } }, + ], }, }, }, @@ -65,13 +59,6 @@ describe('resource threads', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - test('retrieve: request options instead of params are passed correctly', async () => { - // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error - await expect( - client.beta.threads.retrieve('thread_id', { path: '/_stainless_unknown_path' }), - ).rejects.toThrow(OpenAI.NotFoundError); - }); - test('update', async () => { const responsePromise = client.beta.threads.update('thread_id', {}); const rawResponse = await responsePromise.asResponse(); @@ -83,8 +70,8 @@ describe('resource threads', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - test('del', async () => { - const responsePromise = client.beta.threads.del('thread_id'); + test('delete', async () => { + const responsePromise = client.beta.threads.delete('thread_id'); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -94,13 +81,6 @@ describe('resource threads', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - test('del: request options instead of params are passed correctly', async () => { - // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error - await expect(client.beta.threads.del('thread_id', { path: '/_stainless_unknown_path' })).rejects.toThrow( - OpenAI.NotFoundError, - ); - }); - test('createAndRun: only required params', async () => { const responsePromise = client.beta.threads.createAndRun({ assistant_id: 'assistant_id' }); const rawResponse = await responsePromise.asResponse(); @@ -118,7 +98,7 @@ describe('resource threads', () => { instructions: 'instructions', max_completion_tokens: 256, max_prompt_tokens: 256, - metadata: {}, + metadata: { foo: 'string' }, model: 'gpt-4o', parallel_tool_calls: true, response_format: 'auto', @@ -130,15 +110,17 @@ describe('resource threads', () => { content: 'string', role: 'user', attachments: [{ file_id: 'file_id', tools: [{ type: 'code_interpreter' }] }], - metadata: {}, + metadata: { foo: 'string' }, }, ], - metadata: {}, + metadata: { foo: 'string' }, tool_resources: { code_interpreter: { file_ids: ['string'] }, file_search: { vector_store_ids: ['string'], - vector_stores: [{ chunking_strategy: { type: 'auto' }, file_ids: ['string'], metadata: {} }], + vector_stores: [ + { chunking_strategy: { type: 'auto' }, file_ids: ['string'], metadata: { foo: 'string' } }, + ], }, }, }, diff --git a/tests/api-resources/beta/vector-stores/file-batches.test.ts b/tests/api-resources/beta/vector-stores/file-batches.test.ts index b714049b4..783801214 100644 --- a/tests/api-resources/beta/vector-stores/file-batches.test.ts +++ b/tests/api-resources/beta/vector-stores/file-batches.test.ts @@ -1,7 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import OpenAI from 'openai'; -import { Response } from 'node-fetch'; const client = new OpenAI({ apiKey: 'My API Key', @@ -29,8 +28,10 @@ describe('resource fileBatches', () => { }); }); - test('retrieve', async () => { - const responsePromise = client.beta.vectorStores.fileBatches.retrieve('vs_abc123', 'vsfb_abc123'); + test('retrieve: only required params', async () => { + const responsePromise = client.beta.vectorStores.fileBatches.retrieve('vsfb_abc123', { + vector_store_id: 'vs_abc123', + }); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -40,17 +41,16 @@ describe('resource fileBatches', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - test('retrieve: request options instead of params are passed correctly', async () => { - // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error - await expect( - client.beta.vectorStores.fileBatches.retrieve('vs_abc123', 'vsfb_abc123', { - path: '/_stainless_unknown_path', - }), - ).rejects.toThrow(OpenAI.NotFoundError); + test('retrieve: required and optional params', async () => { + const response = await client.beta.vectorStores.fileBatches.retrieve('vsfb_abc123', { + vector_store_id: 'vs_abc123', + }); }); - test('cancel', async () => { - const responsePromise = client.beta.vectorStores.fileBatches.cancel('vector_store_id', 'batch_id'); + test('cancel: only required params', async () => { + const responsePromise = client.beta.vectorStores.fileBatches.cancel('batch_id', { + vector_store_id: 'vector_store_id', + }); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -60,17 +60,16 @@ describe('resource fileBatches', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - test('cancel: request options instead of params are passed correctly', async () => { - // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error - await expect( - client.beta.vectorStores.fileBatches.cancel('vector_store_id', 'batch_id', { - path: '/_stainless_unknown_path', - }), - ).rejects.toThrow(OpenAI.NotFoundError); + test('cancel: required and optional params', async () => { + const response = await client.beta.vectorStores.fileBatches.cancel('batch_id', { + vector_store_id: 'vector_store_id', + }); }); - test('listFiles', async () => { - const responsePromise = client.beta.vectorStores.fileBatches.listFiles('vector_store_id', 'batch_id'); + test('listFiles: only required params', async () => { + const responsePromise = client.beta.vectorStores.fileBatches.listFiles('batch_id', { + vector_store_id: 'vector_store_id', + }); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -80,24 +79,14 @@ describe('resource fileBatches', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - test('listFiles: request options instead of params are passed correctly', async () => { - // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error - await expect( - client.beta.vectorStores.fileBatches.listFiles('vector_store_id', 'batch_id', { - path: '/_stainless_unknown_path', - }), - ).rejects.toThrow(OpenAI.NotFoundError); - }); - - test('listFiles: request options and params are passed correctly', async () => { - // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error - await expect( - client.beta.vectorStores.fileBatches.listFiles( - 'vector_store_id', - 'batch_id', - { after: 'after', before: 'before', filter: 'in_progress', limit: 0, order: 'asc' }, - { path: '/_stainless_unknown_path' }, - ), - ).rejects.toThrow(OpenAI.NotFoundError); + test('listFiles: required and optional params', async () => { + const response = await client.beta.vectorStores.fileBatches.listFiles('batch_id', { + vector_store_id: 'vector_store_id', + after: 'after', + before: 'before', + filter: 'in_progress', + limit: 0, + order: 'asc', + }); }); }); diff --git a/tests/api-resources/beta/vector-stores/files.test.ts b/tests/api-resources/beta/vector-stores/files.test.ts index 7c14d4de3..c32cb6408 100644 --- a/tests/api-resources/beta/vector-stores/files.test.ts +++ b/tests/api-resources/beta/vector-stores/files.test.ts @@ -1,7 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import OpenAI from 'openai'; -import { Response } from 'node-fetch'; const client = new OpenAI({ apiKey: 'My API Key', @@ -27,8 +26,10 @@ describe('resource files', () => { }); }); - test('retrieve', async () => { - const responsePromise = client.beta.vectorStores.files.retrieve('vs_abc123', 'file-abc123'); + test('retrieve: only required params', async () => { + const responsePromise = client.beta.vectorStores.files.retrieve('file-abc123', { + vector_store_id: 'vs_abc123', + }); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -38,13 +39,10 @@ describe('resource files', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - test('retrieve: request options instead of params are passed correctly', async () => { - // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error - await expect( - client.beta.vectorStores.files.retrieve('vs_abc123', 'file-abc123', { - path: '/_stainless_unknown_path', - }), - ).rejects.toThrow(OpenAI.NotFoundError); + test('retrieve: required and optional params', async () => { + const response = await client.beta.vectorStores.files.retrieve('file-abc123', { + vector_store_id: 'vs_abc123', + }); }); test('list', async () => { @@ -58,13 +56,6 @@ describe('resource files', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - test('list: request options instead of params are passed correctly', async () => { - // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error - await expect( - client.beta.vectorStores.files.list('vector_store_id', { path: '/_stainless_unknown_path' }), - ).rejects.toThrow(OpenAI.NotFoundError); - }); - test('list: request options and params are passed correctly', async () => { // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error await expect( @@ -76,8 +67,10 @@ describe('resource files', () => { ).rejects.toThrow(OpenAI.NotFoundError); }); - test('del', async () => { - const responsePromise = client.beta.vectorStores.files.del('vector_store_id', 'file_id'); + test('delete: only required params', async () => { + const responsePromise = client.beta.vectorStores.files.delete('file_id', { + vector_store_id: 'vector_store_id', + }); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -87,10 +80,9 @@ describe('resource files', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - test('del: request options instead of params are passed correctly', async () => { - // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error - await expect( - client.beta.vectorStores.files.del('vector_store_id', 'file_id', { path: '/_stainless_unknown_path' }), - ).rejects.toThrow(OpenAI.NotFoundError); + test('delete: required and optional params', async () => { + const response = await client.beta.vectorStores.files.delete('file_id', { + vector_store_id: 'vector_store_id', + }); }); }); diff --git a/tests/api-resources/beta/vector-stores/vector-stores.test.ts b/tests/api-resources/beta/vector-stores/vector-stores.test.ts index 806098de8..ecb8d33a1 100644 --- a/tests/api-resources/beta/vector-stores/vector-stores.test.ts +++ b/tests/api-resources/beta/vector-stores/vector-stores.test.ts @@ -1,7 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import OpenAI from 'openai'; -import { Response } from 'node-fetch'; const client = new OpenAI({ apiKey: 'My API Key', @@ -31,13 +30,6 @@ describe('resource vectorStores', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - test('retrieve: request options instead of params are passed correctly', async () => { - // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error - await expect( - client.beta.vectorStores.retrieve('vector_store_id', { path: '/_stainless_unknown_path' }), - ).rejects.toThrow(OpenAI.NotFoundError); - }); - test('update', async () => { const responsePromise = client.beta.vectorStores.update('vector_store_id', {}); const rawResponse = await responsePromise.asResponse(); @@ -60,13 +52,6 @@ describe('resource vectorStores', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - test('list: request options instead of params are passed correctly', async () => { - // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error - await expect(client.beta.vectorStores.list({ path: '/_stainless_unknown_path' })).rejects.toThrow( - OpenAI.NotFoundError, - ); - }); - test('list: request options and params are passed correctly', async () => { // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error await expect( @@ -77,8 +62,8 @@ describe('resource vectorStores', () => { ).rejects.toThrow(OpenAI.NotFoundError); }); - test('del', async () => { - const responsePromise = client.beta.vectorStores.del('vector_store_id'); + test('delete', async () => { + const responsePromise = client.beta.vectorStores.delete('vector_store_id'); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -87,11 +72,4 @@ describe('resource vectorStores', () => { expect(dataAndResponse.data).toBe(response); expect(dataAndResponse.response).toBe(rawResponse); }); - - test('del: request options instead of params are passed correctly', async () => { - // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error - await expect( - client.beta.vectorStores.del('vector_store_id', { path: '/_stainless_unknown_path' }), - ).rejects.toThrow(OpenAI.NotFoundError); - }); }); diff --git a/tests/api-resources/chat/completions.test.ts b/tests/api-resources/chat/completions.test.ts deleted file mode 100644 index dfc09f69b..000000000 --- a/tests/api-resources/chat/completions.test.ts +++ /dev/null @@ -1,65 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -import OpenAI from 'openai'; -import { Response } from 'node-fetch'; - -const client = new OpenAI({ - apiKey: 'My API Key', - baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010/', -}); - -describe('resource completions', () => { - test('create: only required params', async () => { - const responsePromise = client.chat.completions.create({ - messages: [{ content: 'string', role: 'developer' }], - model: 'gpt-4o', - }); - const rawResponse = await responsePromise.asResponse(); - expect(rawResponse).toBeInstanceOf(Response); - const response = await responsePromise; - expect(response).not.toBeInstanceOf(Response); - const dataAndResponse = await responsePromise.withResponse(); - expect(dataAndResponse.data).toBe(response); - expect(dataAndResponse.response).toBe(rawResponse); - }); - - test('create: required and optional params', async () => { - const response = await client.chat.completions.create({ - messages: [{ content: 'string', role: 'developer', name: 'name' }], - model: 'gpt-4o', - audio: { format: 'wav', voice: 'alloy' }, - frequency_penalty: -2, - function_call: 'none', - functions: [{ name: 'name', description: 'description', parameters: { foo: 'bar' } }], - logit_bias: { foo: 0 }, - logprobs: true, - max_completion_tokens: 0, - max_tokens: 0, - metadata: { foo: 'string' }, - modalities: ['text'], - n: 1, - parallel_tool_calls: true, - prediction: { content: 'string', type: 'content' }, - presence_penalty: -2, - reasoning_effort: 'low', - response_format: { type: 'text' }, - seed: -9007199254740991, - service_tier: 'auto', - stop: 'string', - store: true, - stream: false, - stream_options: { include_usage: true }, - temperature: 1, - tool_choice: 'none', - tools: [ - { - function: { name: 'name', description: 'description', parameters: { foo: 'bar' }, strict: true }, - type: 'function', - }, - ], - top_logprobs: 0, - top_p: 1, - user: 'user-1234', - }); - }); -}); diff --git a/tests/api-resources/chat/completions/completions.test.ts b/tests/api-resources/chat/completions/completions.test.ts new file mode 100644 index 000000000..5de69484a --- /dev/null +++ b/tests/api-resources/chat/completions/completions.test.ts @@ -0,0 +1,122 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import OpenAI from 'openai'; + +const client = new OpenAI({ + apiKey: 'My API Key', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010/', +}); + +describe('resource completions', () => { + test('create: only required params', async () => { + const responsePromise = client.chat.completions.create({ + messages: [{ content: 'string', role: 'developer' }], + model: 'gpt-4o', + }); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + test('create: required and optional params', async () => { + const response = await client.chat.completions.create({ + messages: [{ content: 'string', role: 'developer', name: 'name' }], + model: 'gpt-4o', + audio: { format: 'wav', voice: 'alloy' }, + frequency_penalty: -2, + function_call: 'none', + functions: [{ name: 'name', description: 'description', parameters: { foo: 'bar' } }], + logit_bias: { foo: 0 }, + logprobs: true, + max_completion_tokens: 0, + max_tokens: 0, + metadata: { foo: 'string' }, + modalities: ['text'], + n: 1, + parallel_tool_calls: true, + prediction: { content: 'string', type: 'content' }, + presence_penalty: -2, + reasoning_effort: 'low', + response_format: { type: 'text' }, + seed: 0, + service_tier: 'auto', + stop: 'string', + store: true, + stream: false, + stream_options: { include_usage: true }, + temperature: 1, + tool_choice: 'none', + tools: [ + { + function: { name: 'name', description: 'description', parameters: { foo: 'bar' }, strict: true }, + type: 'function', + }, + ], + top_logprobs: 0, + top_p: 1, + user: 'user-1234', + }); + }); + + test('retrieve', async () => { + const responsePromise = client.chat.completions.retrieve('completion_id'); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + test('update: only required params', async () => { + const responsePromise = client.chat.completions.update('completion_id', { metadata: { foo: 'string' } }); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + test('update: required and optional params', async () => { + const response = await client.chat.completions.update('completion_id', { metadata: { foo: 'string' } }); + }); + + test('list', async () => { + const responsePromise = client.chat.completions.list(); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + test('list: request options and params are passed correctly', async () => { + // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error + await expect( + client.chat.completions.list( + { after: 'after', limit: 0, metadata: { foo: 'string' }, model: 'model', order: 'asc' }, + { path: '/_stainless_unknown_path' }, + ), + ).rejects.toThrow(OpenAI.NotFoundError); + }); + + test('delete', async () => { + const responsePromise = client.chat.completions.delete('completion_id'); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); +}); diff --git a/tests/api-resources/chat/completions/messages.test.ts b/tests/api-resources/chat/completions/messages.test.ts new file mode 100644 index 000000000..98dd22167 --- /dev/null +++ b/tests/api-resources/chat/completions/messages.test.ts @@ -0,0 +1,32 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import OpenAI from 'openai'; + +const client = new OpenAI({ + apiKey: 'My API Key', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010/', +}); + +describe('resource messages', () => { + test('list', async () => { + const responsePromise = client.chat.completions.messages.list('completion_id'); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + test('list: request options and params are passed correctly', async () => { + // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error + await expect( + client.chat.completions.messages.list( + 'completion_id', + { after: 'after', limit: 0, order: 'asc' }, + { path: '/_stainless_unknown_path' }, + ), + ).rejects.toThrow(OpenAI.NotFoundError); + }); +}); diff --git a/tests/api-resources/completions.test.ts b/tests/api-resources/completions.test.ts index 82322dc3a..a9d188a2b 100644 --- a/tests/api-resources/completions.test.ts +++ b/tests/api-resources/completions.test.ts @@ -1,7 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import OpenAI from 'openai'; -import { Response } from 'node-fetch'; const client = new OpenAI({ apiKey: 'My API Key', @@ -32,7 +31,7 @@ describe('resource completions', () => { max_tokens: 16, n: 1, presence_penalty: -2, - seed: -9007199254740991, + seed: 0, stop: '\n', stream: false, stream_options: { include_usage: true }, diff --git a/tests/api-resources/embeddings.test.ts b/tests/api-resources/embeddings.test.ts index 46dd1b2a3..c449f9825 100644 --- a/tests/api-resources/embeddings.test.ts +++ b/tests/api-resources/embeddings.test.ts @@ -1,7 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import OpenAI from 'openai'; -import { Response } from 'node-fetch'; const client = new OpenAI({ apiKey: 'My API Key', diff --git a/tests/api-resources/files.test.ts b/tests/api-resources/files.test.ts index c907c4987..96c8ac563 100644 --- a/tests/api-resources/files.test.ts +++ b/tests/api-resources/files.test.ts @@ -1,7 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import OpenAI, { toFile } from 'openai'; -import { Response } from 'node-fetch'; const client = new OpenAI({ apiKey: 'My API Key', @@ -41,13 +40,6 @@ describe('resource files', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - test('retrieve: request options instead of params are passed correctly', async () => { - // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error - await expect(client.files.retrieve('file_id', { path: '/_stainless_unknown_path' })).rejects.toThrow( - OpenAI.NotFoundError, - ); - }); - test('list', async () => { const responsePromise = client.files.list(); const rawResponse = await responsePromise.asResponse(); @@ -59,13 +51,6 @@ describe('resource files', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - test('list: request options instead of params are passed correctly', async () => { - // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error - await expect(client.files.list({ path: '/_stainless_unknown_path' })).rejects.toThrow( - OpenAI.NotFoundError, - ); - }); - test('list: request options and params are passed correctly', async () => { // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error await expect( @@ -76,33 +61,8 @@ describe('resource files', () => { ).rejects.toThrow(OpenAI.NotFoundError); }); - test('del', async () => { - const responsePromise = client.files.del('file_id'); - const rawResponse = await responsePromise.asResponse(); - expect(rawResponse).toBeInstanceOf(Response); - const response = await responsePromise; - expect(response).not.toBeInstanceOf(Response); - const dataAndResponse = await responsePromise.withResponse(); - expect(dataAndResponse.data).toBe(response); - expect(dataAndResponse.response).toBe(rawResponse); - }); - - test('del: request options instead of params are passed correctly', async () => { - // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error - await expect(client.files.del('file_id', { path: '/_stainless_unknown_path' })).rejects.toThrow( - OpenAI.NotFoundError, - ); - }); - - test('content: request options instead of params are passed correctly', async () => { - // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error - await expect(client.files.content('file_id', { path: '/_stainless_unknown_path' })).rejects.toThrow( - OpenAI.NotFoundError, - ); - }); - - test('retrieveContent', async () => { - const responsePromise = client.files.retrieveContent('file_id'); + test('delete', async () => { + const responsePromise = client.files.delete('file_id'); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -111,11 +71,4 @@ describe('resource files', () => { expect(dataAndResponse.data).toBe(response); expect(dataAndResponse.response).toBe(rawResponse); }); - - test('retrieveContent: request options instead of params are passed correctly', async () => { - // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error - await expect( - client.files.retrieveContent('file_id', { path: '/_stainless_unknown_path' }), - ).rejects.toThrow(OpenAI.NotFoundError); - }); }); diff --git a/tests/api-resources/fine-tuning/jobs/checkpoints.test.ts b/tests/api-resources/fine-tuning/jobs/checkpoints.test.ts index d211a9b10..6177aee9b 100644 --- a/tests/api-resources/fine-tuning/jobs/checkpoints.test.ts +++ b/tests/api-resources/fine-tuning/jobs/checkpoints.test.ts @@ -1,7 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import OpenAI from 'openai'; -import { Response } from 'node-fetch'; const client = new OpenAI({ apiKey: 'My API Key', @@ -20,15 +19,6 @@ describe('resource checkpoints', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - test('list: request options instead of params are passed correctly', async () => { - // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error - await expect( - client.fineTuning.jobs.checkpoints.list('ft-AF1WoRqd3aJAHsqc9NY7iL8F', { - path: '/_stainless_unknown_path', - }), - ).rejects.toThrow(OpenAI.NotFoundError); - }); - test('list: request options and params are passed correctly', async () => { // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error await expect( diff --git a/tests/api-resources/fine-tuning/jobs/jobs.test.ts b/tests/api-resources/fine-tuning/jobs/jobs.test.ts index 4de83a8b7..b194ac234 100644 --- a/tests/api-resources/fine-tuning/jobs/jobs.test.ts +++ b/tests/api-resources/fine-tuning/jobs/jobs.test.ts @@ -1,7 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import OpenAI from 'openai'; -import { Response } from 'node-fetch'; const client = new OpenAI({ apiKey: 'My API Key', @@ -65,13 +64,6 @@ describe('resource jobs', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - test('retrieve: request options instead of params are passed correctly', async () => { - // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error - await expect( - client.fineTuning.jobs.retrieve('ft-AF1WoRqd3aJAHsqc9NY7iL8F', { path: '/_stainless_unknown_path' }), - ).rejects.toThrow(OpenAI.NotFoundError); - }); - test('list', async () => { const responsePromise = client.fineTuning.jobs.list(); const rawResponse = await responsePromise.asResponse(); @@ -83,13 +75,6 @@ describe('resource jobs', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - test('list: request options instead of params are passed correctly', async () => { - // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error - await expect(client.fineTuning.jobs.list({ path: '/_stainless_unknown_path' })).rejects.toThrow( - OpenAI.NotFoundError, - ); - }); - test('list: request options and params are passed correctly', async () => { // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error await expect( @@ -108,13 +93,6 @@ describe('resource jobs', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - test('cancel: request options instead of params are passed correctly', async () => { - // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error - await expect( - client.fineTuning.jobs.cancel('ft-AF1WoRqd3aJAHsqc9NY7iL8F', { path: '/_stainless_unknown_path' }), - ).rejects.toThrow(OpenAI.NotFoundError); - }); - test('listEvents', async () => { const responsePromise = client.fineTuning.jobs.listEvents('ft-AF1WoRqd3aJAHsqc9NY7iL8F'); const rawResponse = await responsePromise.asResponse(); @@ -126,13 +104,6 @@ describe('resource jobs', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - test('listEvents: request options instead of params are passed correctly', async () => { - // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error - await expect( - client.fineTuning.jobs.listEvents('ft-AF1WoRqd3aJAHsqc9NY7iL8F', { path: '/_stainless_unknown_path' }), - ).rejects.toThrow(OpenAI.NotFoundError); - }); - test('listEvents: request options and params are passed correctly', async () => { // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error await expect( diff --git a/tests/api-resources/images.test.ts b/tests/api-resources/images.test.ts index 88eb97a93..9f00da3b3 100644 --- a/tests/api-resources/images.test.ts +++ b/tests/api-resources/images.test.ts @@ -1,7 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import OpenAI, { toFile } from 'openai'; -import { Response } from 'node-fetch'; const client = new OpenAI({ apiKey: 'My API Key', diff --git a/tests/api-resources/models.test.ts b/tests/api-resources/models.test.ts index 23ebd1bb6..9bf5fbd64 100644 --- a/tests/api-resources/models.test.ts +++ b/tests/api-resources/models.test.ts @@ -1,7 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import OpenAI from 'openai'; -import { Response } from 'node-fetch'; const client = new OpenAI({ apiKey: 'My API Key', @@ -20,13 +19,6 @@ describe('resource models', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - test('retrieve: request options instead of params are passed correctly', async () => { - // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error - await expect(client.models.retrieve('gpt-4o-mini', { path: '/_stainless_unknown_path' })).rejects.toThrow( - OpenAI.NotFoundError, - ); - }); - test('list', async () => { const responsePromise = client.models.list(); const rawResponse = await responsePromise.asResponse(); @@ -38,15 +30,8 @@ describe('resource models', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - test('list: request options instead of params are passed correctly', async () => { - // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error - await expect(client.models.list({ path: '/_stainless_unknown_path' })).rejects.toThrow( - OpenAI.NotFoundError, - ); - }); - - test('del', async () => { - const responsePromise = client.models.del('ft:gpt-4o-mini:acemeco:suffix:abc123'); + test('delete', async () => { + const responsePromise = client.models.delete('ft:gpt-4o-mini:acemeco:suffix:abc123'); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -55,11 +40,4 @@ describe('resource models', () => { expect(dataAndResponse.data).toBe(response); expect(dataAndResponse.response).toBe(rawResponse); }); - - test('del: request options instead of params are passed correctly', async () => { - // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error - await expect( - client.models.del('ft:gpt-4o-mini:acemeco:suffix:abc123', { path: '/_stainless_unknown_path' }), - ).rejects.toThrow(OpenAI.NotFoundError); - }); }); diff --git a/tests/api-resources/moderations.test.ts b/tests/api-resources/moderations.test.ts index 64f9acf3c..d50175b2d 100644 --- a/tests/api-resources/moderations.test.ts +++ b/tests/api-resources/moderations.test.ts @@ -1,7 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import OpenAI from 'openai'; -import { Response } from 'node-fetch'; const client = new OpenAI({ apiKey: 'My API Key', diff --git a/tests/api-resources/uploads/parts.test.ts b/tests/api-resources/uploads/parts.test.ts index e584bab8e..06079e31c 100644 --- a/tests/api-resources/uploads/parts.test.ts +++ b/tests/api-resources/uploads/parts.test.ts @@ -1,7 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import OpenAI, { toFile } from 'openai'; -import { Response } from 'node-fetch'; const client = new OpenAI({ apiKey: 'My API Key', diff --git a/tests/api-resources/uploads/uploads.test.ts b/tests/api-resources/uploads/uploads.test.ts index c9ea4ddd7..19fed99ea 100644 --- a/tests/api-resources/uploads/uploads.test.ts +++ b/tests/api-resources/uploads/uploads.test.ts @@ -1,7 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import OpenAI from 'openai'; -import { Response } from 'node-fetch'; const client = new OpenAI({ apiKey: 'My API Key', @@ -45,13 +44,6 @@ describe('resource uploads', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - test('cancel: request options instead of params are passed correctly', async () => { - // ensure the request options are being passed correctly by passing an invalid HTTP method in order to cause an error - await expect( - client.uploads.cancel('upload_abc123', { path: '/_stainless_unknown_path' }), - ).rejects.toThrow(OpenAI.NotFoundError); - }); - test('complete: only required params', async () => { const responsePromise = client.uploads.complete('upload_abc123', { part_ids: ['string'] }); const rawResponse = await responsePromise.asResponse(); diff --git a/tests/base64.test.ts b/tests/base64.test.ts new file mode 100644 index 000000000..1cb120c2d --- /dev/null +++ b/tests/base64.test.ts @@ -0,0 +1,80 @@ +import { fromBase64, toBase64 } from 'openai/internal/utils/base64'; + +describe.each(['Buffer', 'atob'])('with %s', (mode) => { + let originalBuffer: BufferConstructor; + beforeAll(() => { + if (mode === 'atob') { + originalBuffer = globalThis.Buffer; + // @ts-expect-error Can't assign undefined to BufferConstructor + delete globalThis.Buffer; + } + }); + afterAll(() => { + if (mode === 'atob') { + globalThis.Buffer = originalBuffer; + } + }); + test('toBase64', () => { + const testCases = [ + { + input: 'hello world', + expected: 'aGVsbG8gd29ybGQ=', + }, + { + input: new Uint8Array([104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100]), + expected: 'aGVsbG8gd29ybGQ=', + }, + { + input: undefined, + expected: '', + }, + { + input: new Uint8Array([ + 229, 102, 215, 230, 65, 22, 46, 87, 243, 176, 99, 99, 31, 174, 8, 242, 83, 142, 169, 64, 122, 123, + 193, 71, + ]), + expected: '5WbX5kEWLlfzsGNjH64I8lOOqUB6e8FH', + }, + { + input: '✓', + expected: '4pyT', + }, + { + input: new Uint8Array([226, 156, 147]), + expected: '4pyT', + }, + ]; + + testCases.forEach(({ input, expected }) => { + expect(toBase64(input)).toBe(expected); + }); + }); + + test('fromBase64', () => { + const testCases = [ + { + input: 'aGVsbG8gd29ybGQ=', + expected: new Uint8Array([104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100]), + }, + { + input: '', + expected: new Uint8Array([]), + }, + { + input: '5WbX5kEWLlfzsGNjH64I8lOOqUB6e8FH', + expected: new Uint8Array([ + 229, 102, 215, 230, 65, 22, 46, 87, 243, 176, 99, 99, 31, 174, 8, 242, 83, 142, 169, 64, 122, 123, + 193, 71, + ]), + }, + { + input: '4pyT', + expected: new Uint8Array([226, 156, 147]), + }, + ]; + + testCases.forEach(({ input, expected }) => { + expect(fromBase64(input)).toEqual(expected); + }); + }); +}); diff --git a/tests/buildHeaders.test.ts b/tests/buildHeaders.test.ts new file mode 100644 index 000000000..3f8e4d28e --- /dev/null +++ b/tests/buildHeaders.test.ts @@ -0,0 +1,88 @@ +import { inspect } from 'node:util'; +import { buildHeaders, type HeadersLike, type NullableHeaders } from 'openai/internal/headers'; + +function inspectNullableHeaders(headers: NullableHeaders) { + return `NullableHeaders {${[ + ...[...headers.values.entries()].map(([name, value]) => ` ${inspect(name)}: ${inspect(value)}`), + ...[...headers.nulls].map((name) => ` ${inspect(name)}: null`), + ].join(', ')} }`; +} + +describe('buildHeaders', () => { + const cases: [HeadersLike[], string][] = [ + [[new Headers({ 'content-type': 'text/plain' })], `NullableHeaders { 'content-type': 'text/plain' }`], + [ + [ + { + 'content-type': 'text/plain', + }, + { + 'Content-Type': undefined, + }, + ], + `NullableHeaders { 'content-type': 'text/plain' }`, + ], + [ + [ + { + 'content-type': 'text/plain', + }, + { + 'Content-Type': null, + }, + ], + `NullableHeaders { 'content-type': null }`, + ], + [ + [ + { + cookie: 'name1=value1', + Cookie: 'name2=value2', + }, + ], + `NullableHeaders { 'cookie': 'name2=value2' }`, + ], + [ + [ + { + cookie: 'name1=value1', + Cookie: undefined, + }, + ], + `NullableHeaders { 'cookie': 'name1=value1' }`, + ], + [ + [ + { + cookie: ['name1=value1', 'name2=value2'], + }, + ], + `NullableHeaders { 'cookie': 'name1=value1; name2=value2' }`, + ], + [ + [ + { + 'x-foo': ['name1=value1', 'name2=value2'], + }, + ], + `NullableHeaders { 'x-foo': 'name1=value1, name2=value2' }`, + ], + [ + [ + [ + ['cookie', 'name1=value1'], + ['cookie', 'name2=value2'], + ['Cookie', 'name3=value3'], + ], + ], + `NullableHeaders { 'cookie': 'name1=value1; name2=value2; name3=value3' }`, + ], + [[undefined], `NullableHeaders { }`], + [[null], `NullableHeaders { }`], + ]; + for (const [input, expected] of cases) { + test(expected, () => { + expect(inspectNullableHeaders(buildHeaders(input))).toEqual(expected); + }); + } +}); diff --git a/tests/form.test.ts b/tests/form.test.ts index 3a143852c..5ca5b75f2 100644 --- a/tests/form.test.ts +++ b/tests/form.test.ts @@ -1,65 +1,85 @@ -import { multipartFormRequestOptions, createForm } from 'openai/core'; -import { Blob } from 'openai/_shims/index'; -import { toFile } from 'openai'; +import { multipartFormRequestOptions, createForm } from 'openai/internal/uploads'; +import { toFile } from 'openai/uploads'; describe('form data validation', () => { test('valid values do not error', async () => { - await multipartFormRequestOptions({ - body: { - foo: 'foo', - string: 1, - bool: true, - file: await toFile(Buffer.from('some-content')), - blob: new Blob(['Some content'], { type: 'text/plain' }), + await multipartFormRequestOptions( + { + body: { + foo: 'foo', + string: 1, + bool: true, + file: await toFile(Buffer.from('some-content')), + blob: new Blob(['Some content'], { type: 'text/plain' }), + }, }, - }); + fetch, + ); }); test('null', async () => { await expect(() => - multipartFormRequestOptions({ - body: { - null: null, + multipartFormRequestOptions( + { + body: { + null: null, + }, }, - }), + fetch, + ), ).rejects.toThrow(TypeError); }); test('undefined is stripped', async () => { - const form = await createForm({ - foo: undefined, - bar: 'baz', - }); + const form = await createForm( + { + foo: undefined, + bar: 'baz', + }, + fetch, + ); expect(form.has('foo')).toBe(false); expect(form.get('bar')).toBe('baz'); }); test('nested undefined property is stripped', async () => { - const form = await createForm({ - bar: { - baz: undefined, + const form = await createForm( + { + bar: { + baz: undefined, + }, }, - }); + fetch, + ); expect(Array.from(form.entries())).toEqual([]); - const form2 = await createForm({ - bar: { - foo: 'string', - baz: undefined, + const form2 = await createForm( + { + bar: { + foo: 'string', + baz: undefined, + }, }, - }); + fetch, + ); expect(Array.from(form2.entries())).toEqual([['bar[foo]', 'string']]); }); test('nested undefined array item is stripped', async () => { - const form = await createForm({ - bar: [undefined, undefined], - }); + const form = await createForm( + { + bar: [undefined, undefined], + }, + fetch, + ); expect(Array.from(form.entries())).toEqual([]); - const form2 = await createForm({ - bar: [undefined, 'foo'], - }); + const form2 = await createForm( + { + bar: [undefined, 'foo'], + }, + fetch, + ); expect(Array.from(form2.entries())).toEqual([['bar[]', 'foo']]); }); }); diff --git a/tests/index.test.ts b/tests/index.test.ts index bf113e7bb..07c99ba87 100644 --- a/tests/index.test.ts +++ b/tests/index.test.ts @@ -1,9 +1,11 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +import { APIPromise } from 'openai/api-promise'; + +import util from 'node:util'; import OpenAI from 'openai'; import { APIUserAbortError } from 'openai'; -import { Headers } from 'openai/core'; -import defaultFetch, { Response, type RequestInit, type RequestInfo } from 'node-fetch'; +const defaultFetch = fetch; describe('instantiate client', () => { const env = process.env; @@ -11,8 +13,6 @@ describe('instantiate client', () => { beforeEach(() => { jest.resetModules(); process.env = { ...env }; - - console.warn = jest.fn(); }); afterEach(() => { @@ -28,7 +28,7 @@ describe('instantiate client', () => { test('they are used in the request', () => { const { req } = client.buildRequest({ path: '/foo', method: 'post' }); - expect((req.headers as Headers)['x-my-default-header']).toEqual('2'); + expect(req.headers.get('x-my-default-header')).toEqual('2'); }); test('can ignore `undefined` and leave the default', () => { @@ -37,7 +37,7 @@ describe('instantiate client', () => { method: 'post', headers: { 'X-My-Default-Header': undefined }, }); - expect((req.headers as Headers)['x-my-default-header']).toEqual('2'); + expect(req.headers.get('x-my-default-header')).toEqual('2'); }); test('can be removed with `null`', () => { @@ -46,7 +46,136 @@ describe('instantiate client', () => { method: 'post', headers: { 'X-My-Default-Header': null }, }); - expect(req.headers as Headers).not.toHaveProperty('x-my-default-header'); + expect(req.headers.has('x-my-default-header')).toBe(false); + }); + }); + describe('logging', () => { + const env = process.env; + + beforeEach(() => { + process.env = { ...env }; + process.env['OPENAI_LOG'] = undefined; + }); + + afterEach(() => { + process.env = env; + }); + + const forceAPIResponseForClient = async (client: OpenAI) => { + await new APIPromise( + client, + Promise.resolve({ + response: new Response(), + controller: new AbortController(), + requestLogID: 'log_000000', + retryOfRequestLogID: undefined, + startTime: Date.now(), + options: { + method: 'get', + path: '/', + }, + }), + ); + }; + + test('debug logs when log level is debug', async () => { + const debugMock = jest.fn(); + const logger = { + debug: debugMock, + info: jest.fn(), + warn: jest.fn(), + error: jest.fn(), + }; + + const client = new OpenAI({ logger: logger, logLevel: 'debug', apiKey: 'My API Key' }); + + await forceAPIResponseForClient(client); + expect(debugMock).toHaveBeenCalled(); + }); + + test('default logLevel is warn', async () => { + const client = new OpenAI({ apiKey: 'My API Key' }); + expect(client.logLevel).toBe('warn'); + }); + + test('debug logs are skipped when log level is info', async () => { + const debugMock = jest.fn(); + const logger = { + debug: debugMock, + info: jest.fn(), + warn: jest.fn(), + error: jest.fn(), + }; + + const client = new OpenAI({ logger: logger, logLevel: 'info', apiKey: 'My API Key' }); + + await forceAPIResponseForClient(client); + expect(debugMock).not.toHaveBeenCalled(); + }); + + test('debug logs happen with debug env var', async () => { + const debugMock = jest.fn(); + const logger = { + debug: debugMock, + info: jest.fn(), + warn: jest.fn(), + error: jest.fn(), + }; + + process.env['OPENAI_LOG'] = 'debug'; + const client = new OpenAI({ logger: logger, apiKey: 'My API Key' }); + expect(client.logLevel).toBe('debug'); + + await forceAPIResponseForClient(client); + expect(debugMock).toHaveBeenCalled(); + }); + + test('warn when env var level is invalid', async () => { + const warnMock = jest.fn(); + const logger = { + debug: jest.fn(), + info: jest.fn(), + warn: warnMock, + error: jest.fn(), + }; + + process.env['OPENAI_LOG'] = 'not a log level'; + const client = new OpenAI({ logger: logger, apiKey: 'My API Key' }); + expect(client.logLevel).toBe('warn'); + expect(warnMock).toHaveBeenCalledWith( + 'process.env[\'OPENAI_LOG\'] was set to "not a log level", expected one of ["off","error","warn","info","debug"]', + ); + }); + + test('client log level overrides env var', async () => { + const debugMock = jest.fn(); + const logger = { + debug: debugMock, + info: jest.fn(), + warn: jest.fn(), + error: jest.fn(), + }; + + process.env['OPENAI_LOG'] = 'debug'; + const client = new OpenAI({ logger: logger, logLevel: 'off', apiKey: 'My API Key' }); + + await forceAPIResponseForClient(client); + expect(debugMock).not.toHaveBeenCalled(); + }); + + test('no warning logged for invalid env var level + valid client level', async () => { + const warnMock = jest.fn(); + const logger = { + debug: jest.fn(), + info: jest.fn(), + warn: warnMock, + error: jest.fn(), + }; + + process.env['OPENAI_LOG'] = 'not a log level'; + const client = new OpenAI({ logger: logger, logLevel: 'debug', apiKey: 'My API Key' }); + expect(client.logLevel).toBe('debug'); + expect(warnMock).not.toHaveBeenCalled(); }); }); @@ -96,6 +225,15 @@ describe('instantiate client', () => { expect(response).toEqual({ url: 'http://localhost:5000/foo', custom: true }); }); + test('explicit global fetch', async () => { + // make sure the global fetch type is assignable to our Fetch type + const client = new OpenAI({ + baseURL: 'http://localhost:5000/', + apiKey: 'My API Key', + fetch: defaultFetch, + }); + }); + test('custom signal', async () => { const client = new OpenAI({ baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010/', @@ -122,6 +260,19 @@ describe('instantiate client', () => { expect(spy).toHaveBeenCalledTimes(1); }); + test('normalized method', async () => { + let capturedRequest: RequestInit | undefined; + const testFetch = async (url: string | URL | Request, init: RequestInit = {}): Promise => { + capturedRequest = init; + return new Response(JSON.stringify({}), { headers: { 'Content-Type': 'application/json' } }); + }; + + const client = new OpenAI({ baseURL: 'http://localhost:5000/', apiKey: 'My API Key', fetch: testFetch }); + + await client.patch('/foo'); + expect(capturedRequest?.method).toEqual('PATCH'); + }); + describe('baseUrl', () => { test('trailing slash', () => { const client = new OpenAI({ baseURL: 'http://localhost:5000/custom/path/', apiKey: 'My API Key' }); @@ -188,18 +339,6 @@ describe('instantiate client', () => { describe('request building', () => { const client = new OpenAI({ apiKey: 'My API Key' }); - describe('Content-Length', () => { - test('handles multi-byte characters', () => { - const { req } = client.buildRequest({ path: '/foo', method: 'post', body: { value: '—' } }); - expect((req.headers as Record)['content-length']).toEqual('20'); - }); - - test('handles standard characters', () => { - const { req } = client.buildRequest({ path: '/foo', method: 'post', body: { value: 'hello' } }); - expect((req.headers as Record)['content-length']).toEqual('22'); - }); - }); - describe('custom headers', () => { test('handles undefined', () => { const { req } = client.buildRequest({ @@ -208,18 +347,92 @@ describe('request building', () => { body: { value: 'hello' }, headers: { 'X-Foo': 'baz', 'x-foo': 'bar', 'x-Foo': undefined, 'x-baz': 'bam', 'X-Baz': null }, }); - expect((req.headers as Record)['x-foo']).toEqual('bar'); - expect((req.headers as Record)['x-Foo']).toEqual(undefined); - expect((req.headers as Record)['X-Foo']).toEqual(undefined); - expect((req.headers as Record)['x-baz']).toEqual(undefined); + expect(req.headers.get('x-foo')).toEqual('bar'); + expect(req.headers.get('x-Foo')).toEqual('bar'); + expect(req.headers.get('X-Foo')).toEqual('bar'); + expect(req.headers.get('x-baz')).toEqual(null); }); }); }); +describe('default encoder', () => { + const client = new OpenAI({ apiKey: 'My API Key' }); + + class Serializable { + toJSON() { + return { $type: 'Serializable' }; + } + } + class Collection { + #things: T[]; + constructor(things: T[]) { + this.#things = Array.from(things); + } + toJSON() { + return Array.from(this.#things); + } + [Symbol.iterator]() { + return this.#things[Symbol.iterator]; + } + } + for (const jsonValue of [{}, [], { __proto__: null }, new Serializable(), new Collection(['item'])]) { + test(`serializes ${util.inspect(jsonValue)} as json`, () => { + const { req } = client.buildRequest({ + path: '/foo', + method: 'post', + body: jsonValue, + }); + expect(req.headers).toBeInstanceOf(Headers); + expect(req.headers.get('content-type')).toEqual('application/json'); + expect(req.body).toBe(JSON.stringify(jsonValue)); + }); + } + + const encoder = new TextEncoder(); + const asyncIterable = (async function* () { + yield encoder.encode('a\n'); + yield encoder.encode('b\n'); + yield encoder.encode('c\n'); + })(); + for (const streamValue of [ + [encoder.encode('a\nb\nc\n')][Symbol.iterator](), + new Response('a\nb\nc\n').body, + asyncIterable, + ]) { + test(`converts ${util.inspect(streamValue)} to ReadableStream`, async () => { + const { req } = client.buildRequest({ + path: '/foo', + method: 'post', + body: streamValue, + }); + expect(req.headers).toBeInstanceOf(Headers); + expect(req.headers.get('content-type')).toEqual(null); + expect(req.body).toBeInstanceOf(ReadableStream); + expect(await new Response(req.body).text()).toBe('a\nb\nc\n'); + }); + } + + test(`can set content-type for ReadableStream`, async () => { + const { req } = client.buildRequest({ + path: '/foo', + method: 'post', + body: new Response('a\nb\nc\n').body, + headers: { 'Content-Type': 'text/plain' }, + }); + expect(req.headers).toBeInstanceOf(Headers); + expect(req.headers.get('content-type')).toEqual('text/plain'); + expect(req.body).toBeInstanceOf(ReadableStream); + expect(await new Response(req.body).text()).toBe('a\nb\nc\n'); + }); +}); + describe('retries', () => { test('retry on timeout', async () => { let count = 0; - const testFetch = async (url: RequestInfo, { signal }: RequestInit = {}): Promise => { + const testFetch = async ( + url: string | URL | Request, + { signal }: RequestInit = {}, + ): Promise => { if (count++ === 0) { return new Promise( (resolve, reject) => signal?.addEventListener('abort', () => reject(new Error('timed out'))), @@ -244,7 +457,7 @@ describe('retries', () => { test('retry count header', async () => { let count = 0; let capturedRequest: RequestInit | undefined; - const testFetch = async (url: RequestInfo, init: RequestInit = {}): Promise => { + const testFetch = async (url: string | URL | Request, init: RequestInit = {}): Promise => { count++; if (count <= 2) { return new Response(undefined, { @@ -262,14 +475,14 @@ describe('retries', () => { expect(await client.request({ path: '/foo', method: 'get' })).toEqual({ a: 1 }); - expect((capturedRequest!.headers as Headers)['x-stainless-retry-count']).toEqual('2'); + expect((capturedRequest!.headers as Headers).get('x-stainless-retry-count')).toEqual('2'); expect(count).toEqual(3); }); test('omit retry count header', async () => { let count = 0; let capturedRequest: RequestInit | undefined; - const testFetch = async (url: RequestInfo, init: RequestInit = {}): Promise => { + const testFetch = async (url: string | URL | Request, init: RequestInit = {}): Promise => { count++; if (count <= 2) { return new Response(undefined, { @@ -292,13 +505,13 @@ describe('retries', () => { }), ).toEqual({ a: 1 }); - expect(capturedRequest!.headers as Headers).not.toHaveProperty('x-stainless-retry-count'); + expect((capturedRequest!.headers as Headers).has('x-stainless-retry-count')).toBe(false); }); test('omit retry count header by default', async () => { let count = 0; let capturedRequest: RequestInit | undefined; - const testFetch = async (url: RequestInfo, init: RequestInit = {}): Promise => { + const testFetch = async (url: string | URL | Request, init: RequestInit = {}): Promise => { count++; if (count <= 2) { return new Response(undefined, { @@ -331,7 +544,7 @@ describe('retries', () => { test('overwrite retry count header', async () => { let count = 0; let capturedRequest: RequestInit | undefined; - const testFetch = async (url: RequestInfo, init: RequestInit = {}): Promise => { + const testFetch = async (url: string | URL | Request, init: RequestInit = {}): Promise => { count++; if (count <= 2) { return new Response(undefined, { @@ -354,12 +567,15 @@ describe('retries', () => { }), ).toEqual({ a: 1 }); - expect((capturedRequest!.headers as Headers)['x-stainless-retry-count']).toBe('42'); + expect((capturedRequest!.headers as Headers).get('x-stainless-retry-count')).toEqual('42'); }); test('retry on 429 with retry-after', async () => { let count = 0; - const testFetch = async (url: RequestInfo, { signal }: RequestInit = {}): Promise => { + const testFetch = async ( + url: string | URL | Request, + { signal }: RequestInit = {}, + ): Promise => { if (count++ === 0) { return new Response(undefined, { status: 429, @@ -386,7 +602,10 @@ describe('retries', () => { test('retry on 429 with retry-after-ms', async () => { let count = 0; - const testFetch = async (url: RequestInfo, { signal }: RequestInit = {}): Promise => { + const testFetch = async ( + url: string | URL | Request, + { signal }: RequestInit = {}, + ): Promise => { if (count++ === 0) { return new Response(undefined, { status: 429, diff --git a/tests/internal/decoders/line.test.ts b/tests/internal/decoders/line.test.ts new file mode 100644 index 000000000..e76858e55 --- /dev/null +++ b/tests/internal/decoders/line.test.ts @@ -0,0 +1,128 @@ +import { findDoubleNewlineIndex, LineDecoder } from 'openai/internal/decoders/line'; + +function decodeChunks(chunks: string[], { flush }: { flush: boolean } = { flush: false }): string[] { + const decoder = new LineDecoder(); + const lines: string[] = []; + for (const chunk of chunks) { + lines.push(...decoder.decode(chunk)); + } + + if (flush) { + lines.push(...decoder.flush()); + } + + return lines; +} + +describe('line decoder', () => { + test('basic', () => { + // baz is not included because the line hasn't ended yet + expect(decodeChunks(['foo', ' bar\nbaz'])).toEqual(['foo bar']); + }); + + test('basic with \\r', () => { + expect(decodeChunks(['foo', ' bar\r\nbaz'])).toEqual(['foo bar']); + expect(decodeChunks(['foo', ' bar\r\nbaz'], { flush: true })).toEqual(['foo bar', 'baz']); + }); + + test('trailing new lines', () => { + expect(decodeChunks(['foo', ' bar', 'baz\n', 'thing\n'])).toEqual(['foo barbaz', 'thing']); + }); + + test('trailing new lines with \\r', () => { + expect(decodeChunks(['foo', ' bar', 'baz\r\n', 'thing\r\n'])).toEqual(['foo barbaz', 'thing']); + }); + + test('escaped new lines', () => { + expect(decodeChunks(['foo', ' bar\\nbaz\n'])).toEqual(['foo bar\\nbaz']); + }); + + test('escaped new lines with \\r', () => { + expect(decodeChunks(['foo', ' bar\\r\\nbaz\n'])).toEqual(['foo bar\\r\\nbaz']); + }); + + test('\\r & \\n split across multiple chunks', () => { + expect(decodeChunks(['foo\r', '\n', 'bar'], { flush: true })).toEqual(['foo', 'bar']); + }); + + test('single \\r', () => { + expect(decodeChunks(['foo\r', 'bar'], { flush: true })).toEqual(['foo', 'bar']); + }); + + test('double \\r', () => { + expect(decodeChunks(['foo\r', 'bar\r'], { flush: true })).toEqual(['foo', 'bar']); + expect(decodeChunks(['foo\r', '\r', 'bar'], { flush: true })).toEqual(['foo', '', 'bar']); + // implementation detail that we don't yield the single \r line until a new \r or \n is encountered + expect(decodeChunks(['foo\r', '\r', 'bar'], { flush: false })).toEqual(['foo']); + }); + + test('double \\r then \\r\\n', () => { + expect(decodeChunks(['foo\r', '\r', '\r', '\n', 'bar', '\n'])).toEqual(['foo', '', '', 'bar']); + expect(decodeChunks(['foo\n', '\n', '\n', 'bar', '\n'])).toEqual(['foo', '', '', 'bar']); + }); + + test('double newline', () => { + expect(decodeChunks(['foo\n\nbar'], { flush: true })).toEqual(['foo', '', 'bar']); + expect(decodeChunks(['foo', '\n', '\nbar'], { flush: true })).toEqual(['foo', '', 'bar']); + expect(decodeChunks(['foo\n', '\n', 'bar'], { flush: true })).toEqual(['foo', '', 'bar']); + expect(decodeChunks(['foo', '\n', '\n', 'bar'], { flush: true })).toEqual(['foo', '', 'bar']); + }); + + test('multi-byte characters across chunks', () => { + const decoder = new LineDecoder(); + + // bytes taken from the string 'известни' and arbitrarily split + // so that some multi-byte characters span multiple chunks + expect(decoder.decode(new Uint8Array([0xd0]))).toHaveLength(0); + expect(decoder.decode(new Uint8Array([0xb8, 0xd0, 0xb7, 0xd0]))).toHaveLength(0); + expect( + decoder.decode(new Uint8Array([0xb2, 0xd0, 0xb5, 0xd1, 0x81, 0xd1, 0x82, 0xd0, 0xbd, 0xd0, 0xb8])), + ).toHaveLength(0); + + const decoded = decoder.decode(new Uint8Array([0xa])); + expect(decoded).toEqual(['известни']); + }); + + test('flushing trailing newlines', () => { + expect(decodeChunks(['foo\n', '\nbar'], { flush: true })).toEqual(['foo', '', 'bar']); + }); + + test('flushing empty buffer', () => { + expect(decodeChunks([], { flush: true })).toEqual([]); + }); +}); + +describe('findDoubleNewlineIndex', () => { + test('finds \\n\\n', () => { + expect(findDoubleNewlineIndex(new TextEncoder().encode('foo\n\nbar'))).toBe(5); + expect(findDoubleNewlineIndex(new TextEncoder().encode('\n\nbar'))).toBe(2); + expect(findDoubleNewlineIndex(new TextEncoder().encode('foo\n\n'))).toBe(5); + expect(findDoubleNewlineIndex(new TextEncoder().encode('\n\n'))).toBe(2); + }); + + test('finds \\r\\r', () => { + expect(findDoubleNewlineIndex(new TextEncoder().encode('foo\r\rbar'))).toBe(5); + expect(findDoubleNewlineIndex(new TextEncoder().encode('\r\rbar'))).toBe(2); + expect(findDoubleNewlineIndex(new TextEncoder().encode('foo\r\r'))).toBe(5); + expect(findDoubleNewlineIndex(new TextEncoder().encode('\r\r'))).toBe(2); + }); + + test('finds \\r\\n\\r\\n', () => { + expect(findDoubleNewlineIndex(new TextEncoder().encode('foo\r\n\r\nbar'))).toBe(7); + expect(findDoubleNewlineIndex(new TextEncoder().encode('\r\n\r\nbar'))).toBe(4); + expect(findDoubleNewlineIndex(new TextEncoder().encode('foo\r\n\r\n'))).toBe(7); + expect(findDoubleNewlineIndex(new TextEncoder().encode('\r\n\r\n'))).toBe(4); + }); + + test('returns -1 when no double newline found', () => { + expect(findDoubleNewlineIndex(new TextEncoder().encode('foo\nbar'))).toBe(-1); + expect(findDoubleNewlineIndex(new TextEncoder().encode('foo\rbar'))).toBe(-1); + expect(findDoubleNewlineIndex(new TextEncoder().encode('foo\r\nbar'))).toBe(-1); + expect(findDoubleNewlineIndex(new TextEncoder().encode(''))).toBe(-1); + }); + + test('handles incomplete patterns', () => { + expect(findDoubleNewlineIndex(new TextEncoder().encode('foo\r\n\r'))).toBe(-1); + expect(findDoubleNewlineIndex(new TextEncoder().encode('foo\r\n'))).toBe(-1); + }); +}); diff --git a/tests/lib/ChatCompletionRunFunctions.test.ts b/tests/lib/ChatCompletionRunFunctions.test.ts index b684f204d..f2ce1c029 100644 --- a/tests/lib/ChatCompletionRunFunctions.test.ts +++ b/tests/lib/ChatCompletionRunFunctions.test.ts @@ -4,12 +4,11 @@ import { PassThrough } from 'stream'; import { ParsingToolFunction, type ChatCompletionRunner, - type ChatCompletionFunctionRunnerParams, + type ChatCompletionToolRunnerParams, ChatCompletionStreamingRunner, - type ChatCompletionStreamingFunctionRunnerParams, + type ChatCompletionStreamingToolRunnerParams, } from 'openai/resources/beta/chat/completions'; import type { ChatCompletionMessageParam } from 'openai/resources/chat/completions'; -import { Response } from 'node-fetch'; import { isAssistantMessage } from '../../src/lib/chatCompletionUtils'; import { mockFetch } from '../utils/mock-fetch'; @@ -19,12 +18,12 @@ function mockChatCompletionFetch() { const { fetch, handleRequest: handleRawRequest } = mockFetch(); function handleRequest( - handler: (body: ChatCompletionFunctionRunnerParams) => Promise, + handler: (body: ChatCompletionToolRunnerParams) => Promise, ): Promise { return handleRawRequest(async (req, init) => { const rawBody = init?.body; if (typeof rawBody !== 'string') throw new Error(`expected init.body to be a string`); - const body: ChatCompletionFunctionRunnerParams = JSON.parse(rawBody); + const body: ChatCompletionToolRunnerParams = JSON.parse(rawBody); return new Response(JSON.stringify(await handler(body)), { headers: { 'Content-Type': 'application/json' }, }); @@ -40,13 +39,13 @@ function mockStreamingChatCompletionFetch() { function handleRequest( handler: ( - body: ChatCompletionStreamingFunctionRunnerParams, + body: ChatCompletionStreamingToolRunnerParams, ) => AsyncIterable, ): Promise { return handleRawRequest(async (req, init) => { const rawBody = init?.body; if (typeof rawBody !== 'string') throw new Error(`expected init.body to be a string`); - const body: ChatCompletionStreamingFunctionRunnerParams = JSON.parse(rawBody); + const body: ChatCompletionStreamingToolRunnerParams = JSON.parse(rawBody); const stream = new PassThrough(); (async () => { for await (const chunk of handler(body)) { @@ -628,7 +627,7 @@ describe('resource completions', () => { content: "it's raining", parsed: null, refusal: null, - tool_calls: [], + tool_calls: undefined, }, ]); expect(listener.functionCallResults).toEqual([`it's raining`]); @@ -876,7 +875,7 @@ describe('resource completions', () => { content: 'there are 3 properties in {"a": 1, "b": 2, "c": 3}', parsed: null, refusal: null, - tool_calls: [], + tool_calls: undefined, }, ]); expect(listener.functionCallResults).toEqual(['3']); @@ -1125,7 +1124,7 @@ describe('resource completions', () => { content: 'there are 3 properties in {"a": 1, "b": 2, "c": 3}', parsed: null, refusal: null, - tool_calls: [], + tool_calls: undefined, }, ]); expect(listener.functionCallResults).toEqual([`must be an object`, '3']); @@ -1443,7 +1442,7 @@ describe('resource completions', () => { content: "it's raining", parsed: null, refusal: null, - tool_calls: [], + tool_calls: undefined, }, ]); expect(listener.functionCallResults).toEqual([ @@ -1572,7 +1571,7 @@ describe('resource completions', () => { content: "it's raining", parsed: null, refusal: null, - tool_calls: [], + tool_calls: undefined, }, ]); expect(listener.eventFunctionCallResults).toEqual([`it's raining`]); @@ -1795,7 +1794,7 @@ describe('resource completions', () => { content: 'there are 3 properties in {"a": 1, "b": 2, "c": 3}', parsed: null, refusal: null, - tool_calls: [], + tool_calls: undefined, }, ]); expect(listener.eventFunctionCallResults).toEqual(['3']); @@ -1997,7 +1996,7 @@ describe('resource completions', () => { content: 'there are 3 properties in {"a": 1, "b": 2, "c": 3}', parsed: null, refusal: null, - tool_calls: [], + tool_calls: undefined, }, ]); expect(listener.eventFunctionCallResults).toEqual([`must be an object`, '3']); @@ -2301,7 +2300,7 @@ describe('resource completions', () => { content: "it's raining", parsed: null, refusal: null, - tool_calls: [], + tool_calls: undefined, }, ]); expect(listener.eventFunctionCallResults).toEqual([ @@ -2347,7 +2346,7 @@ describe('resource completions', () => { content: 'The weather is great today!', parsed: null, refusal: null, - tool_calls: [], + tool_calls: undefined, }); await listener.sanityCheck(); }); @@ -2386,7 +2385,7 @@ describe('resource completions', () => { content: 'The weather is great today!', parsed: null, refusal: null, - tool_calls: [], + tool_calls: undefined, }); await listener.sanityCheck(); }); diff --git a/tests/lib/ChatCompletionStream.test.ts b/tests/lib/ChatCompletionStream.test.ts index e5ef20c9e..34c5fd204 100644 --- a/tests/lib/ChatCompletionStream.test.ts +++ b/tests/lib/ChatCompletionStream.test.ts @@ -39,7 +39,6 @@ describe('.stream()', () => { }, "refusal": null, "role": "assistant", - "tool_calls": [], }, } `); @@ -198,7 +197,6 @@ describe('.stream()', () => { }, "refusal": null, "role": "assistant", - "tool_calls": [], }, } `); @@ -386,7 +384,6 @@ describe('.stream()', () => { "parsed": null, "refusal": "I'm very sorry, but I can't assist with that request.", "role": "assistant", - "tool_calls": [], }, } `); diff --git a/tests/lib/azure.test.ts b/tests/lib/azure.test.ts index 064a0098c..1b9b2546c 100644 --- a/tests/lib/azure.test.ts +++ b/tests/lib/azure.test.ts @@ -1,7 +1,9 @@ import { AzureOpenAI } from 'openai'; import { APIUserAbortError } from 'openai'; -import { Headers } from 'openai/core'; -import defaultFetch, { Response, type RequestInit, type RequestInfo } from 'node-fetch'; +import { type Response, RequestInit, RequestInfo } from 'openai/internal/builtin-types'; +import { File } from 'node:buffer'; + +const defaultFetch = fetch; const apiVersion = '2024-02-15-preview'; const deployment = 'deployment'; @@ -31,7 +33,7 @@ describe('instantiate azure client', () => { test('they are used in the request', () => { const { req } = client.buildRequest({ path: '/foo', method: 'post' }); - expect((req.headers as Headers)['x-my-default-header']).toEqual('2'); + expect(req.headers.get('x-my-default-header')).toEqual('2'); }); test('can ignore `undefined` and leave the default', () => { @@ -40,7 +42,7 @@ describe('instantiate azure client', () => { method: 'post', headers: { 'X-My-Default-Header': undefined }, }); - expect((req.headers as Headers)['x-my-default-header']).toEqual('2'); + expect(req.headers.get('x-my-default-header')).toEqual('2'); }); test('can be removed with `null`', () => { @@ -49,7 +51,7 @@ describe('instantiate azure client', () => { method: 'post', headers: { 'X-My-Default-Header': null }, }); - expect(req.headers as Headers).not.toHaveProperty('x-my-default-header'); + expect(req.headers.has('x-my-default-header')).toBe(false); }); }); @@ -226,7 +228,7 @@ describe('instantiate azure client', () => { describe('Azure Active Directory (AD)', () => { test('with azureADTokenProvider', async () => { const testFetch = async (url: RequestInfo, { headers }: RequestInit = {}): Promise => { - return new Response(JSON.stringify({ a: 1 }), { headers }); + return new Response(JSON.stringify({ a: 1 }), { headers: headers ?? [] }); }; const client = new AzureOpenAI({ baseURL: 'http://localhost:5000/', @@ -255,7 +257,7 @@ describe('instantiate azure client', () => { ); }); - test('AAD token is refreshed', async () => { + test.skip('AAD token is refreshed', async () => { let fail = true; const testFetch = async (url: RequestInfo, req: RequestInit | undefined): Promise => { if (fail) { @@ -267,10 +269,9 @@ describe('instantiate azure client', () => { }, }); } - return new Response( - JSON.stringify({ auth: (req?.headers as Record)['authorization'] }), - { headers: { 'content-type': 'application/json' } }, - ); + return new Response(JSON.stringify({ auth: (req?.headers as Headers).get('authorization') }), { + headers: { 'content-type': 'application/json' }, + }); }; let counter = 0; async function azureADTokenProvider() { @@ -315,10 +316,8 @@ describe('azure request building', () => { const client = new AzureOpenAI({ baseURL: 'https://example.com/', apiKey: 'My API Key', apiVersion }); describe('model to deployment mapping', function () { - const testFetch = async (url: RequestInfo, { body }: RequestInit = {}): Promise => { - return new Response(JSON.stringify({ url, body }), { - headers: { 'content-type': 'application/json' }, - }); + const testFetch = async (url: RequestInfo): Promise => { + return new Response(JSON.stringify({ url }), { headers: { 'content-type': 'application/json' } }); }; describe('with client-level deployment', function () { const client = new AzureOpenAI({ @@ -329,110 +328,128 @@ describe('azure request building', () => { fetch: testFetch, }); - test('handles batch', async () => { - const { url } = (await client.batches.create({ - completion_window: '24h', - endpoint: '/v1/chat/completions', - input_file_id: 'file-id', - })) as any; - expect(url).toStrictEqual(`https://example.com/openai/batches?api-version=${apiVersion}`); + test('handles Batch', async () => { + expect( + await client.batches.create({ + completion_window: '24h', + endpoint: '/v1/chat/completions', + input_file_id: 'file-id', + }), + ).toMatchObject({ + url: `https://example.com/openai/deployments/${deployment}/batches?api-version=${apiVersion}`, + }); }); test('handles completions', async () => { - const { url } = (await client.completions.create({ - model, - prompt: 'prompt', - })) as any; - expect(url).toStrictEqual( - `https://example.com/openai/deployments/${deployment}/completions?api-version=${apiVersion}`, - ); + expect( + await client.completions.create({ + model, + prompt: 'prompt', + }), + ).toMatchObject({ + url: `https://example.com/openai/deployments/${deployment}/completions?api-version=${apiVersion}`, + }); }); test('handles chat completions', async () => { - const { url } = (await client.chat.completions.create({ - model, - messages: [{ role: 'system', content: 'Hello' }], - })) as any; - expect(url).toStrictEqual( - `https://example.com/openai/deployments/${deployment}/chat/completions?api-version=${apiVersion}`, - ); + expect( + await client.chat.completions.create({ + model, + messages: [{ role: 'system', content: 'Hello' }], + }), + ).toMatchObject({ + url: `https://example.com/openai/deployments/${deployment}/chat/completions?api-version=${apiVersion}`, + }); }); test('handles embeddings', async () => { - const { url } = (await client.embeddings.create({ - model, - input: 'input', - })) as any; - expect(url).toStrictEqual( - `https://example.com/openai/deployments/${deployment}/embeddings?api-version=${apiVersion}`, - ); + expect( + await client.embeddings.create({ + model, + input: 'input', + }), + ).toMatchObject({ + url: `https://example.com/openai/deployments/${deployment}/embeddings?api-version=${apiVersion}`, + }); }); test('handles audio translations', async () => { - const { url } = (await client.audio.translations.create({ - model, - file: { url: 'https://example.com/', blob: () => 0 as any }, - })) as any; - expect(url).toStrictEqual( - `https://example.com/openai/deployments/${deployment}/audio/translations?api-version=${apiVersion}`, - ); + expect( + await client.audio.translations.create({ + model, + file: new File([], ''), + }), + ).toMatchObject({ + url: `https://example.com/openai/deployments/${deployment}/audio/translations?api-version=${apiVersion}`, + }); }); test('handles audio transcriptions', async () => { - const { url } = (await client.audio.transcriptions.create({ - model, - file: { url: 'https://example.com/', blob: () => 0 as any }, - })) as any; - expect(url).toStrictEqual( - `https://example.com/openai/deployments/${deployment}/audio/transcriptions?api-version=${apiVersion}`, - ); + expect( + await client.audio.transcriptions.create({ + model, + file: new File([], ''), + }), + ).toMatchObject({ + url: `https://example.com/openai/deployments/${deployment}/audio/transcriptions?api-version=${apiVersion}`, + }); }); test('handles text to speech', async () => { - const { url, body } = await ( - await client.audio.speech.create({ - model, - input: '', - voice: 'alloy', - }) - ).json(); - expect(url).toStrictEqual( - `https://example.com/openai/deployments/${deployment}/audio/speech?api-version=${apiVersion}`, - ); - expect(body).toMatch(new RegExp(`"model": "${model}"`)); + expect( + await ( + await client.audio.speech.create({ + model, + input: '', + voice: 'alloy', + }) + ).json(), + ).toMatchObject({ + url: `https://example.com/openai/deployments/${deployment}/audio/speech?api-version=${apiVersion}`, + }); }); test('handles image generation', async () => { - const { url } = (await client.images.generate({ - model, - prompt: 'prompt', - })) as any; - expect(url).toStrictEqual( - `https://example.com/openai/deployments/${deployment}/images/generations?api-version=${apiVersion}`, - ); + expect( + await client.images.generate({ + model, + prompt: 'prompt', + }), + ).toMatchObject({ + url: `https://example.com/openai/deployments/${deployment}/images/generations?api-version=${apiVersion}`, + }); }); test('handles assistants', async () => { - const { url } = (await client.beta.assistants.create({ - model, - })) as any; - expect(url).toStrictEqual(`https://example.com/openai/assistants?api-version=${apiVersion}`); + expect( + await client.beta.assistants.create({ + model, + }), + ).toMatchObject({ + url: `https://example.com/openai/assistants?api-version=${apiVersion}`, + }); }); test('handles files', async () => { - const { url } = (await client.files.create({ - file: { url: 'https://example.com/', blob: () => 0 as any }, - purpose: 'assistants', - })) as any; - expect(url).toStrictEqual(`https://example.com/openai/files?api-version=${apiVersion}`); + expect( + await client.files.create({ + file: new File([], ''), + purpose: 'assistants', + }), + ).toMatchObject({ + url: `https://example.com/openai/files?api-version=${apiVersion}`, + }); }); test('handles fine tuning', async () => { - const { url } = (await client.fineTuning.jobs.create({ - model, - training_file: '', - })) as any; - expect(url).toStrictEqual(`https://example.com/openai/fine_tuning/jobs?api-version=${apiVersion}`); + expect( + await client.fineTuning.jobs.create({ + model, + training_file: '', + }), + ).toMatchObject({ + url: `https://example.com/openai/fine_tuning/jobs?api-version=${apiVersion}`, + }); }); }); @@ -444,124 +461,132 @@ describe('azure request building', () => { fetch: testFetch, }); - test('handles batch', async () => { - const { url } = (await client.batches.create({ - completion_window: '24h', - endpoint: '/v1/chat/completions', - input_file_id: 'file-id', - })) as any; - expect(url).toStrictEqual(`https://example.com/openai/batches?api-version=${apiVersion}`); + test('Batch is not handled', async () => { + expect( + await client.batches.create({ + completion_window: '24h', + endpoint: '/v1/chat/completions', + input_file_id: 'file-id', + }), + ).toMatchObject({ + url: `https://example.com/openai/batches?api-version=${apiVersion}`, + }); }); test('handles completions', async () => { - const { url } = (await client.completions.create({ - model: deployment, - prompt: 'prompt', - })) as any; - expect(url).toStrictEqual( - `https://example.com/openai/deployments/${deployment}/completions?api-version=${apiVersion}`, - ); + expect( + await client.completions.create({ + model: deployment, + prompt: 'prompt', + }), + ).toMatchObject({ + url: `https://example.com/openai/deployments/${deployment}/completions?api-version=${apiVersion}`, + }); }); test('handles chat completions', async () => { - const { url } = (await client.chat.completions.create({ - model: deployment, - messages: [{ role: 'system', content: 'Hello' }], - })) as any; - expect(url).toStrictEqual( - `https://example.com/openai/deployments/${deployment}/chat/completions?api-version=${apiVersion}`, - ); + expect( + await client.chat.completions.create({ + model: deployment, + messages: [{ role: 'system', content: 'Hello' }], + }), + ).toMatchObject({ + url: `https://example.com/openai/deployments/${deployment}/chat/completions?api-version=${apiVersion}`, + }); }); test('handles embeddings', async () => { - const { url } = (await client.embeddings.create({ - model: deployment, - input: 'input', - })) as any; - expect(url).toStrictEqual( - `https://example.com/openai/deployments/${deployment}/embeddings?api-version=${apiVersion}`, - ); + expect( + await client.embeddings.create({ + model: deployment, + input: 'input', + }), + ).toMatchObject({ + url: `https://example.com/openai/deployments/${deployment}/embeddings?api-version=${apiVersion}`, + }); }); - test('Audio translations is not handled', async () => { - const { url } = (await client.audio.translations.create({ - model: deployment, - file: { url: 'https://example.com/', blob: () => 0 as any }, - })) as any; - expect(url).toStrictEqual(`https://example.com/openai/audio/translations?api-version=${apiVersion}`); + test('handles audio translations', async () => { + expect( + await client.audio.translations.create({ + model: deployment, + file: new File([], ''), + }), + ).toMatchObject({ + url: `https://example.com/openai/deployments/${deployment}/audio/translations?api-version=${apiVersion}`, + }); }); - test('Audio transcriptions is not handled', async () => { - const { url } = (await client.audio.transcriptions.create({ - model: deployment, - file: { url: 'https://example.com/', blob: () => 0 as any }, - })) as any; - expect(url).toStrictEqual( - `https://example.com/openai/audio/transcriptions?api-version=${apiVersion}`, - ); + test('handles audio transcriptions', async () => { + expect( + await client.audio.transcriptions.create({ + model: deployment, + file: new File([], ''), + }), + ).toMatchObject({ + url: `https://example.com/openai/deployments/${deployment}/audio/transcriptions?api-version=${apiVersion}`, + }); }); test('handles text to speech', async () => { - const { url, body } = await ( - await client.audio.speech.create({ - model: deployment, - input: '', - voice: 'alloy', - }) - ).json(); - expect(url).toStrictEqual( - `https://example.com/openai/deployments/${deployment}/audio/speech?api-version=${apiVersion}`, - ); - expect(body).toMatch(new RegExp(`"model": "${deployment}"`)); + expect( + await ( + await client.audio.speech.create({ + model: deployment, + input: '', + voice: 'alloy', + }) + ).json(), + ).toMatchObject({ + url: `https://example.com/openai/deployments/${deployment}/audio/speech?api-version=${apiVersion}`, + }); }); test('handles image generation', async () => { - const { url } = (await client.images.generate({ - model: deployment, - prompt: 'prompt', - })) as any; - expect(url).toStrictEqual( - `https://example.com/openai/deployments/${deployment}/images/generations?api-version=${apiVersion}`, - ); + expect( + await client.images.generate({ + model: deployment, + prompt: 'prompt', + }), + ).toMatchObject({ + url: `https://example.com/openai/deployments/${deployment}/images/generations?api-version=${apiVersion}`, + }); }); test('handles assistants', async () => { - const { url } = (await client.beta.assistants.create({ - model, - })) as any; - expect(url).toStrictEqual(`https://example.com/openai/assistants?api-version=${apiVersion}`); + expect( + await client.beta.assistants.create({ + model, + }), + ).toMatchObject({ + url: `https://example.com/openai/assistants?api-version=${apiVersion}`, + }); }); test('handles files', async () => { - const { url } = (await client.files.create({ - file: { url: 'https://example.com/', blob: () => 0 as any }, - purpose: 'assistants', - })) as any; - expect(url).toStrictEqual(`https://example.com/openai/files?api-version=${apiVersion}`); + expect( + await client.files.create({ + file: new File([], ''), + purpose: 'assistants', + }), + ).toMatchObject({ + url: `https://example.com/openai/files?api-version=${apiVersion}`, + }); }); test('handles fine tuning', async () => { - const { url } = (await client.fineTuning.jobs.create({ - model: deployment, - training_file: '', - })) as any; - expect(url).toStrictEqual(`https://example.com/openai/fine_tuning/jobs?api-version=${apiVersion}`); + expect( + await client.fineTuning.jobs.create({ + model, + training_file: '', + }), + ).toMatchObject({ + url: `https://example.com/openai/fine_tuning/jobs?api-version=${apiVersion}`, + }); }); }); }); - describe('Content-Length', () => { - test('handles multi-byte characters', () => { - const { req } = client.buildRequest({ path: '/foo', method: 'post', body: { value: '—' } }); - expect((req.headers as Record)['content-length']).toEqual('20'); - }); - - test('handles standard characters', () => { - const { req } = client.buildRequest({ path: '/foo', method: 'post', body: { value: 'hello' } }); - expect((req.headers as Record)['content-length']).toEqual('22'); - }); - }); - describe('custom headers', () => { test('handles undefined', () => { const { req } = client.buildRequest({ @@ -570,10 +595,10 @@ describe('azure request building', () => { body: { value: 'hello' }, headers: { 'X-Foo': 'baz', 'x-foo': 'bar', 'x-Foo': undefined, 'x-baz': 'bam', 'X-Baz': null }, }); - expect((req.headers as Record)['x-foo']).toEqual('bar'); - expect((req.headers as Record)['x-Foo']).toEqual(undefined); - expect((req.headers as Record)['X-Foo']).toEqual(undefined); - expect((req.headers as Record)['x-baz']).toEqual(undefined); + expect(req.headers.get('x-foo')).toEqual('bar'); + expect(req.headers.get('x-Foo')).toEqual('bar'); + expect(req.headers.get('X-Foo')).toEqual('bar'); + expect(req.headers.get('x-baz')).toEqual(null); }); }); }); diff --git a/tests/lib/parser.test.ts b/tests/lib/parser.test.ts index b220e92d3..fa8123f5c 100644 --- a/tests/lib/parser.test.ts +++ b/tests/lib/parser.test.ts @@ -39,7 +39,6 @@ describe('.parse()', () => { }, "refusal": null, "role": "assistant", - "tool_calls": [], }, } `); @@ -154,7 +153,6 @@ describe('.parse()', () => { }, "refusal": null, "role": "assistant", - "tool_calls": [], } `); @@ -488,7 +486,6 @@ describe('.parse()', () => { }, "refusal": null, "role": "assistant", - "tool_calls": [], } `); }); @@ -787,7 +784,6 @@ describe('.parse()', () => { }, "refusal": null, "role": "assistant", - "tool_calls": [], } `); }); @@ -947,7 +943,6 @@ describe('.parse()', () => { }, "refusal": null, "role": "assistant", - "tool_calls": [], } `); }); @@ -1061,7 +1056,6 @@ describe('.parse()', () => { }, "refusal": null, "role": "assistant", - "tool_calls": [], } `); }); diff --git a/tests/path.test.ts b/tests/path.test.ts new file mode 100644 index 000000000..832e4a676 --- /dev/null +++ b/tests/path.test.ts @@ -0,0 +1,318 @@ +import { createPathTagFunction, encodeURIPath } from 'openai/internal/utils/path'; +import { inspect } from 'node:util'; + +describe('path template tag function', () => { + test('validates input', () => { + const testParams = ['', '.', '..', 'x', '%2e', '%2E', '%2e%2e', '%2E%2e', '%2e%2E', '%2E%2E']; + const testCases = [ + ['/path_params/', '/a'], + ['/path_params/', '/'], + ['/path_params/', ''], + ['', '/a'], + ['', '/'], + ['', ''], + ['a'], + [''], + ['/path_params/', ':initiate'], + ['/path_params/', '.json'], + ['/path_params/', '?beta=true'], + ['/path_params/', '.?beta=true'], + ['/path_params/', '/', '/download'], + ['/path_params/', '-', '/download'], + ['/path_params/', '', '/download'], + ['/path_params/', '.', '/download'], + ['/path_params/', '..', '/download'], + ['/plain/path'], + ]; + + function paramPermutations(len: number): string[][] { + if (len === 0) return []; + if (len === 1) return testParams.map((e) => [e]); + const rest = paramPermutations(len - 1); + return testParams.flatMap((e) => rest.map((r) => [e, ...r])); + } + + // we need to test how %2E is handled so we use a custom encoder that does no escaping + const rawPath = createPathTagFunction((s) => s); + + const results: { + [pathParts: string]: { + [params: string]: { valid: boolean; result?: string; error?: string }; + }; + } = {}; + + for (const pathParts of testCases) { + const pathResults: Record = {}; + results[JSON.stringify(pathParts)] = pathResults; + for (const params of paramPermutations(pathParts.length - 1)) { + const stringRaw = String.raw({ raw: pathParts }, ...params); + const plainString = String.raw( + { raw: pathParts.map((e) => e.replace(/\./g, 'x')) }, + ...params.map((e) => 'X'.repeat(e.length)), + ); + const normalizedStringRaw = new URL(stringRaw, 'https://example.com/').href; + const normalizedPlainString = new URL(plainString, 'https://example.com/').href; + const pathResultsKey = JSON.stringify(params); + try { + const result = rawPath(pathParts, ...params); + expect(result).toBe(stringRaw); + // there are no special segments, so the length of the normalized path is + // equal to the length of the normalized plain path. + expect(normalizedStringRaw.length).toBe(normalizedPlainString.length); + pathResults[pathResultsKey] = { + valid: true, + result, + }; + } catch (e) { + const error = String(e); + expect(error).toMatch(/Path parameters result in path with invalid segment/); + // there are special segments, so the length of the normalized path is + // different than the length of the normalized plain path. + expect(normalizedStringRaw.length).not.toBe(normalizedPlainString.length); + pathResults[pathResultsKey] = { + valid: false, + error, + }; + } + } + } + + expect(results).toMatchObject({ + '["/path_params/","/a"]': { + '["x"]': { valid: true, result: '/path_params/x/a' }, + '[""]': { valid: true, result: '/path_params//a' }, + '["%2E%2e"]': { + valid: false, + error: + 'Error: Path parameters result in path with invalid segments:\n' + + '/path_params/%2E%2e/a\n' + + ' ^^^^^^', + }, + '["%2E"]': { + valid: false, + error: + 'Error: Path parameters result in path with invalid segments:\n' + + '/path_params/%2E/a\n' + + ' ^^^', + }, + }, + '["/path_params/","/"]': { + '["x"]': { valid: true, result: '/path_params/x/' }, + '[""]': { valid: true, result: '/path_params//' }, + '["%2e%2E"]': { + valid: false, + error: + 'Error: Path parameters result in path with invalid segments:\n' + + '/path_params/%2e%2E/\n' + + ' ^^^^^^', + }, + '["%2e"]': { + valid: false, + error: + 'Error: Path parameters result in path with invalid segments:\n' + + '/path_params/%2e/\n' + + ' ^^^', + }, + }, + '["/path_params/",""]': { + '[""]': { valid: true, result: '/path_params/' }, + '["x"]': { valid: true, result: '/path_params/x' }, + '["%2E"]': { + valid: false, + error: + 'Error: Path parameters result in path with invalid segments:\n' + + '/path_params/%2E\n' + + ' ^^^', + }, + '["%2E%2e"]': { + valid: false, + error: + 'Error: Path parameters result in path with invalid segments:\n' + + '/path_params/%2E%2e\n' + + ' ^^^^^^', + }, + }, + '["","/a"]': { + '[""]': { valid: true, result: '/a' }, + '["x"]': { valid: true, result: 'x/a' }, + '["%2E"]': { + valid: false, + error: 'Error: Path parameters result in path with invalid segments:\n%2E/a\n^^^', + }, + '["%2e%2E"]': { + valid: false, + error: 'Error: Path parameters result in path with invalid segments:\n' + '%2e%2E/a\n' + '^^^^^^', + }, + }, + '["","/"]': { + '["x"]': { valid: true, result: 'x/' }, + '[""]': { valid: true, result: '/' }, + '["%2E%2e"]': { + valid: false, + error: 'Error: Path parameters result in path with invalid segments:\n' + '%2E%2e/\n' + '^^^^^^', + }, + '["."]': { + valid: false, + error: 'Error: Path parameters result in path with invalid segments:\n./\n^', + }, + }, + '["",""]': { + '[""]': { valid: true, result: '' }, + '["x"]': { valid: true, result: 'x' }, + '[".."]': { + valid: false, + error: 'Error: Path parameters result in path with invalid segments:\n..\n^^', + }, + '["."]': { + valid: false, + error: 'Error: Path parameters result in path with invalid segments:\n.\n^', + }, + }, + '["a"]': {}, + '[""]': {}, + '["/path_params/",":initiate"]': { + '[""]': { valid: true, result: '/path_params/:initiate' }, + '["."]': { valid: true, result: '/path_params/.:initiate' }, + }, + '["/path_params/",".json"]': { + '["x"]': { valid: true, result: '/path_params/x.json' }, + '["."]': { valid: true, result: '/path_params/..json' }, + }, + '["/path_params/","?beta=true"]': { + '["x"]': { valid: true, result: '/path_params/x?beta=true' }, + '[""]': { valid: true, result: '/path_params/?beta=true' }, + '["%2E%2E"]': { + valid: false, + error: + 'Error: Path parameters result in path with invalid segments:\n' + + '/path_params/%2E%2E?beta=true\n' + + ' ^^^^^^', + }, + '["%2e%2E"]': { + valid: false, + error: + 'Error: Path parameters result in path with invalid segments:\n' + + '/path_params/%2e%2E?beta=true\n' + + ' ^^^^^^', + }, + }, + '["/path_params/",".?beta=true"]': { + '[".."]': { valid: true, result: '/path_params/...?beta=true' }, + '["x"]': { valid: true, result: '/path_params/x.?beta=true' }, + '[""]': { + valid: false, + error: + 'Error: Path parameters result in path with invalid segments:\n' + + '/path_params/.?beta=true\n' + + ' ^', + }, + '["%2e"]': { + valid: false, + error: + 'Error: Path parameters result in path with invalid segments:\n' + + '/path_params/%2e.?beta=true\n' + + ' ^^^^', + }, + }, + '["/path_params/","/","/download"]': { + '["",""]': { valid: true, result: '/path_params///download' }, + '["","x"]': { valid: true, result: '/path_params//x/download' }, + '[".","%2e"]': { + valid: false, + error: + 'Error: Path parameters result in path with invalid segments:\n' + + '/path_params/./%2e/download\n' + + ' ^ ^^^', + }, + '["%2E%2e","%2e"]': { + valid: false, + error: + 'Error: Path parameters result in path with invalid segments:\n' + + '/path_params/%2E%2e/%2e/download\n' + + ' ^^^^^^ ^^^', + }, + }, + '["/path_params/","-","/download"]': { + '["","%2e"]': { valid: true, result: '/path_params/-%2e/download' }, + '["%2E",".."]': { valid: true, result: '/path_params/%2E-../download' }, + }, + '["/path_params/","","/download"]': { + '["%2E%2e","%2e%2E"]': { valid: true, result: '/path_params/%2E%2e%2e%2E/download' }, + '["%2E",".."]': { valid: true, result: '/path_params/%2E../download' }, + '["","%2E"]': { + valid: false, + error: + 'Error: Path parameters result in path with invalid segments:\n' + + '/path_params/%2E/download\n' + + ' ^^^', + }, + '["%2E","."]': { + valid: false, + error: + 'Error: Path parameters result in path with invalid segments:\n' + + '/path_params/%2E./download\n' + + ' ^^^^', + }, + }, + '["/path_params/",".","/download"]': { + '["%2e%2e",""]': { valid: true, result: '/path_params/%2e%2e./download' }, + '["","%2e%2e"]': { valid: true, result: '/path_params/.%2e%2e/download' }, + '["",""]': { + valid: false, + error: + 'Error: Path parameters result in path with invalid segments:\n' + + '/path_params/./download\n' + + ' ^', + }, + '["","."]': { + valid: false, + error: + 'Error: Path parameters result in path with invalid segments:\n' + + '/path_params/../download\n' + + ' ^^', + }, + }, + '["/path_params/","..","/download"]': { + '["","%2E"]': { valid: true, result: '/path_params/..%2E/download' }, + '["","x"]': { valid: true, result: '/path_params/..x/download' }, + '["",""]': { + valid: false, + error: + 'Error: Path parameters result in path with invalid segments:\n' + + '/path_params/../download\n' + + ' ^^', + }, + }, + }); + }); +}); + +describe('encodeURIPath', () => { + const testCases: string[] = [ + '', + // Every ASCII character + ...Array.from({ length: 0x7f }, (_, i) => String.fromCharCode(i)), + // Unicode BMP codepoint + 'å', + // Unicode supplementary codepoint + '😃', + ]; + + for (const param of testCases) { + test('properly encodes ' + inspect(param), () => { + const encoded = encodeURIPath(param); + const naiveEncoded = encodeURIComponent(param); + // we should never encode more characters than encodeURIComponent + expect(naiveEncoded.length).toBeGreaterThanOrEqual(encoded.length); + expect(decodeURIComponent(encoded)).toBe(param); + }); + } + + test("leaves ':' intact", () => { + expect(encodeURIPath(':')).toBe(':'); + }); + + test("leaves '@' intact", () => { + expect(encodeURIPath('@')).toBe('@'); + }); +}); diff --git a/tests/qs/utils.test.ts b/tests/qs/utils.test.ts index 3df95e5bd..f97b125ea 100644 --- a/tests/qs/utils.test.ts +++ b/tests/qs/utils.test.ts @@ -66,7 +66,7 @@ describe('merge()', function () { // st.equal(getCount, 1); expect(setCount).toEqual(0); expect(getCount).toEqual(1); - observed[0] = observed[0]; // eslint-disable-line no-self-assign + observed[0] = observed[0]; // st.equal(setCount, 1); // st.equal(getCount, 2); expect(setCount).toEqual(1); diff --git a/tests/responses.test.ts b/tests/responses.test.ts index 527763465..b8a3db906 100644 --- a/tests/responses.test.ts +++ b/tests/responses.test.ts @@ -1,31 +1,8 @@ -import { APIPromise, createResponseHeaders } from 'openai/core'; +import { APIPromise } from 'openai/api-promise'; import OpenAI from 'openai/index'; -import { Headers } from 'openai/_shims/index'; -import { Response } from 'node-fetch'; import { compareType } from './utils/typing'; -describe('response parsing', () => { - // TODO: test unicode characters - test('headers are case agnostic', async () => { - const headers = createResponseHeaders(new Headers({ 'Content-Type': 'foo', Accept: 'text/plain' })); - expect(headers['content-type']).toEqual('foo'); - expect(headers['Content-type']).toEqual('foo'); - expect(headers['Content-Type']).toEqual('foo'); - expect(headers['accept']).toEqual('text/plain'); - expect(headers['Accept']).toEqual('text/plain'); - expect(headers['Hello-World']).toBeUndefined(); - }); - - test('duplicate headers are concatenated', () => { - const headers = createResponseHeaders( - new Headers([ - ['Content-Type', 'text/xml'], - ['Content-Type', 'application/json'], - ]), - ); - expect(headers['content-type']).toBe('text/xml, application/json'); - }); -}); +const client = new OpenAI({ apiKey: '...' }); describe('request id', () => { test('types', () => { @@ -79,6 +56,7 @@ describe('request id', () => { test('envelope response', async () => { const promise = new APIPromise<{ data: { foo: string } }>( + client, (async () => { return { response: new Response(JSON.stringify({ data: { foo: 'bar' } }), { @@ -86,6 +64,9 @@ describe('request id', () => { }), controller: {} as any, options: {} as any, + requestLogID: 'log_...', + retryOfRequestLogID: undefined, + startTime: Date.now(), }; })(), )._thenUnwrap((d) => d.data); @@ -111,6 +92,7 @@ describe('request id', () => { test('array response', async () => { const promise = new APIPromise>( + client, (async () => { return { response: new Response(JSON.stringify([{ foo: 'bar' }]), { @@ -118,6 +100,9 @@ describe('request id', () => { }), controller: {} as any, options: {} as any, + requestLogID: 'log_...', + retryOfRequestLogID: undefined, + startTime: Date.now(), }; })(), ); @@ -130,6 +115,7 @@ describe('request id', () => { test('string response', async () => { const promise = new APIPromise( + client, (async () => { return { response: new Response('hello world', { @@ -137,6 +123,9 @@ describe('request id', () => { }), controller: {} as any, options: {} as any, + requestLogID: 'log_...', + retryOfRequestLogID: undefined, + startTime: Date.now(), }; })(), ); diff --git a/tests/streaming.test.ts b/tests/streaming.test.ts index 6fe9a5781..857cf4620 100644 --- a/tests/streaming.test.ts +++ b/tests/streaming.test.ts @@ -1,35 +1,6 @@ -import { Response } from 'node-fetch'; -import { PassThrough } from 'stream'; import assert from 'assert'; -import { _iterSSEMessages, _decodeChunks as decodeChunks } from 'openai/streaming'; - -describe('line decoder', () => { - test('basic', () => { - // baz is not included because the line hasn't ended yet - expect(decodeChunks(['foo', ' bar\nbaz'])).toEqual(['foo bar']); - }); - - test('basic with \\r', () => { - // baz is not included because the line hasn't ended yet - expect(decodeChunks(['foo', ' bar\r\nbaz'])).toEqual(['foo bar']); - }); - - test('trailing new lines', () => { - expect(decodeChunks(['foo', ' bar', 'baz\n', 'thing\n'])).toEqual(['foo barbaz', 'thing']); - }); - - test('trailing new lines with \\r', () => { - expect(decodeChunks(['foo', ' bar', 'baz\r\n', 'thing\r\n'])).toEqual(['foo barbaz', 'thing']); - }); - - test('escaped new lines', () => { - expect(decodeChunks(['foo', ' bar\\nbaz\n'])).toEqual(['foo bar\\nbaz']); - }); - - test('escaped new lines with \\r', () => { - expect(decodeChunks(['foo', ' bar\\r\\nbaz\n'])).toEqual(['foo bar\\r\\nbaz']); - }); -}); +import { _iterSSEMessages } from 'openai/streaming'; +import { ReadableStreamFrom } from 'openai/internal/shims'; describe('streaming decoding', () => { test('basic', async () => { @@ -39,7 +10,7 @@ describe('streaming decoding', () => { yield Buffer.from('\n'); } - const stream = _iterSSEMessages(new Response(await iteratorToStream(body())), new AbortController())[ + const stream = _iterSSEMessages(new Response(ReadableStreamFrom(body())), new AbortController())[ Symbol.asyncIterator ](); @@ -57,7 +28,7 @@ describe('streaming decoding', () => { yield Buffer.from('\n'); } - const stream = _iterSSEMessages(new Response(await iteratorToStream(body())), new AbortController())[ + const stream = _iterSSEMessages(new Response(ReadableStreamFrom(body())), new AbortController())[ Symbol.asyncIterator ](); @@ -76,7 +47,7 @@ describe('streaming decoding', () => { yield Buffer.from('\n'); } - const stream = _iterSSEMessages(new Response(await iteratorToStream(body())), new AbortController())[ + const stream = _iterSSEMessages(new Response(ReadableStreamFrom(body())), new AbortController())[ Symbol.asyncIterator ](); @@ -97,7 +68,7 @@ describe('streaming decoding', () => { yield Buffer.from('\n'); } - const stream = _iterSSEMessages(new Response(await iteratorToStream(body())), new AbortController())[ + const stream = _iterSSEMessages(new Response(ReadableStreamFrom(body())), new AbortController())[ Symbol.asyncIterator ](); @@ -125,7 +96,7 @@ describe('streaming decoding', () => { yield Buffer.from('\n'); } - const stream = _iterSSEMessages(new Response(await iteratorToStream(body())), new AbortController())[ + const stream = _iterSSEMessages(new Response(ReadableStreamFrom(body())), new AbortController())[ Symbol.asyncIterator ](); @@ -154,7 +125,7 @@ describe('streaming decoding', () => { yield Buffer.from('\n\n'); } - const stream = _iterSSEMessages(new Response(await iteratorToStream(body())), new AbortController())[ + const stream = _iterSSEMessages(new Response(ReadableStreamFrom(body())), new AbortController())[ Symbol.asyncIterator ](); @@ -175,7 +146,7 @@ describe('streaming decoding', () => { yield Buffer.from('\n\n'); } - const stream = _iterSSEMessages(new Response(await iteratorToStream(body())), new AbortController())[ + const stream = _iterSSEMessages(new Response(ReadableStreamFrom(body())), new AbortController())[ Symbol.asyncIterator ](); @@ -200,7 +171,7 @@ describe('streaming decoding', () => { yield Buffer.from('\n'); } - const stream = _iterSSEMessages(new Response(await iteratorToStream(body())), new AbortController())[ + const stream = _iterSSEMessages(new Response(ReadableStreamFrom(body())), new AbortController())[ Symbol.asyncIterator ](); @@ -233,7 +204,7 @@ describe('streaming decoding', () => { yield Buffer.from('\n'); } - const stream = _iterSSEMessages(new Response(await iteratorToStream(body())), new AbortController())[ + const stream = _iterSSEMessages(new Response(ReadableStreamFrom(body())), new AbortController())[ Symbol.asyncIterator ](); @@ -246,27 +217,3 @@ describe('streaming decoding', () => { expect(event.done).toBeTruthy(); }); }); - -async function iteratorToStream(iterator: AsyncGenerator): Promise { - const parts: unknown[] = []; - - for await (const chunk of iterator) { - parts.push(chunk); - } - - let index = 0; - - const stream = new PassThrough({ - read() { - const value = parts[index]; - if (value === undefined) { - stream.end(); - } else { - index += 1; - stream.write(value); - } - }, - }); - - return stream; -} diff --git a/tests/uploads.test.ts b/tests/uploads.test.ts index b64b80285..508fce58f 100644 --- a/tests/uploads.test.ts +++ b/tests/uploads.test.ts @@ -1,6 +1,7 @@ import fs from 'fs'; -import { toFile, type ResponseLike } from 'openai/uploads'; -import { File } from 'openai/_shims/index'; +import type { ResponseLike } from 'openai/internal/to-file'; +import { toFile } from 'openai/uploads'; +import { File } from 'node:buffer'; class MyClass { name: string = 'foo'; @@ -9,7 +10,7 @@ class MyClass { function mockResponse({ url, content }: { url: string; content?: Blob }): ResponseLike { return { url, - blob: async () => content as any, + blob: async () => content || new Blob([]), }; } @@ -62,4 +63,45 @@ describe('toFile', () => { expect(file.name).toEqual('input.jsonl'); expect(file.type).toBe('jsonl'); }); + + it('is assignable to File and Blob', async () => { + const input = new File(['foo'], 'input.jsonl', { type: 'jsonl' }); + const result = await toFile(input); + const file: File = result; + const blob: Blob = result; + void file, blob; + }); +}); + +describe('missing File error message', () => { + let prevGlobalFile: unknown; + let prevNodeFile: unknown; + beforeEach(() => { + // The file shim captures the global File object when it's first imported. + // Reset modules before each test so we can test the error thrown when it's undefined. + jest.resetModules(); + const buffer = require('node:buffer'); + // @ts-ignore + prevGlobalFile = globalThis.File; + prevNodeFile = buffer.File; + // @ts-ignore + globalThis.File = undefined; + buffer.File = undefined; + }); + afterEach(() => { + // Clean up + // @ts-ignore + globalThis.File = prevGlobalFile; + require('node:buffer').File = prevNodeFile; + jest.resetModules(); + }); + + test('is thrown', async () => { + const uploads = await import('openai/uploads'); + await expect( + uploads.toFile(mockResponse({ url: 'https://example.com/my/audio.mp3' })), + ).rejects.toMatchInlineSnapshot( + `[Error: \`File\` is not defined as a global which is required for file uploads]`, + ); + }); }); diff --git a/tests/utils/mock-fetch.ts b/tests/utils/mock-fetch.ts index e122f7aec..f8b2184f5 100644 --- a/tests/utils/mock-fetch.ts +++ b/tests/utils/mock-fetch.ts @@ -1,7 +1,4 @@ -import { type RequestInfo, type RequestInit } from 'openai/_shims/index'; -import { Response } from 'node-fetch'; - -type Fetch = (req: string | RequestInfo, init?: RequestInit) => Promise; +import { type Fetch, type RequestInfo, type RequestInit, type Response } from 'openai/internal/builtin-types'; /** * Creates a mock `fetch` function and a `handleRequest` function for intercepting `fetch` calls. diff --git a/tests/utils/mock-snapshots.ts b/tests/utils/mock-snapshots.ts index 317bf6b0f..fc6b5abd2 100644 --- a/tests/utils/mock-snapshots.ts +++ b/tests/utils/mock-snapshots.ts @@ -1,10 +1,10 @@ -import defaultFetch, { Response } from 'node-fetch'; import OpenAI from 'openai/index'; -import { RequestInit } from 'openai/_shims/auto/types'; -import { RequestInfo } from 'openai/_shims/auto/types'; +import { RequestInfo } from 'openai/internal/builtin-types'; import { mockFetch } from './mock-fetch'; import { Readable } from 'stream'; +const defaultFetch = fetch; + export async function makeSnapshotRequest( requestFn: (client: OpenAI) => Promise, snapshotIndex = 1, diff --git a/tsconfig.build.json b/tsconfig.build.json index 45811cb8b..664392bed 100644 --- a/tsconfig.build.json +++ b/tsconfig.build.json @@ -1,7 +1,7 @@ { "extends": "./tsconfig.json", "include": ["dist/src"], - "exclude": ["dist/src/_shims/*-deno.ts"], + "exclude": [], "compilerOptions": { "rootDir": "./dist/src", "paths": { diff --git a/tsconfig.dist-src.json b/tsconfig.dist-src.json index e9f2d70b0..c550e2996 100644 --- a/tsconfig.dist-src.json +++ b/tsconfig.dist-src.json @@ -4,8 +4,8 @@ // via declaration maps "include": ["index.ts"], "compilerOptions": { - "target": "es2015", - "lib": ["DOM"], + "target": "ES2015", + "lib": ["DOM", "DOM.Iterable", "ES2018"], "moduleResolution": "node" } } diff --git a/tsconfig.json b/tsconfig.json index 33767f7b1..02c80162e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,6 @@ { "include": ["src", "tests", "examples"], - "exclude": ["src/_shims/**/*-deno.ts"], + "exclude": [], "compilerOptions": { "target": "es2020", "lib": ["es2020"], @@ -9,7 +9,6 @@ "esModuleInterop": true, "baseUrl": "./", "paths": { - "openai/_shims/auto/*": ["src/_shims/auto/*-node"], "openai/*": ["src/*"], "openai": ["src/index.ts"] }, diff --git a/yarn.lock b/yarn.lock index c0220f984..b8808db07 100644 --- a/yarn.lock +++ b/yarn.lock @@ -15,6 +15,37 @@ "@jridgewell/gen-mapping" "^0.3.0" "@jridgewell/trace-mapping" "^0.3.9" +"@andrewbranch/untar.js@^1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@andrewbranch/untar.js/-/untar.js-1.0.3.tgz#ba9494f85eb83017c5c855763969caf1d0adea00" + integrity sha512-Jh15/qVmrLGhkKJBdXlK1+9tY4lZruYjsgkDFj08ZmDiWVBLJcqkok7Z0/R0In+i1rScBpJlSvrTS2Lm41Pbnw== + +"@arethetypeswrong/cli@^0.17.0": + version "0.17.0" + resolved "https://registry.yarnpkg.com/@arethetypeswrong/cli/-/cli-0.17.0.tgz#f97f10926b3f9f9eb5117550242d2e06c25cadac" + integrity sha512-xSMW7bfzVWpYw5JFgZqBXqr6PdR0/REmn3DkxCES5N0JTcB0CVgbIynJCvKBFmXaPc3hzmmTrb7+yPDRoOSZdA== + dependencies: + "@arethetypeswrong/core" "0.17.0" + chalk "^4.1.2" + cli-table3 "^0.6.3" + commander "^10.0.1" + marked "^9.1.2" + marked-terminal "^7.1.0" + semver "^7.5.4" + +"@arethetypeswrong/core@0.17.0": + version "0.17.0" + resolved "https://registry.yarnpkg.com/@arethetypeswrong/core/-/core-0.17.0.tgz#abb3b5f425056d37193644c2a2de4aecf866b76b" + integrity sha512-FHyhFizXNetigTVsIhqXKGYLpazPS5YNojEPpZEUcBPt9wVvoEbNIvG+hybuBR+pjlRcbyuqhukHZm1fr+bDgA== + dependencies: + "@andrewbranch/untar.js" "^1.0.3" + cjs-module-lexer "^1.2.3" + fflate "^0.8.2" + lru-cache "^10.4.3" + semver "^7.5.4" + typescript "5.6.1-rc" + validate-npm-package-name "^5.0.0" + "@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.22.13", "@babel/code-frame@^7.23.5": version "7.23.5" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.23.5.tgz#9009b69a8c602293476ad598ff53e4562e15c244" @@ -302,6 +333,11 @@ resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== +"@colors/colors@1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9" + integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ== + "@cspotcode/source-map-consumer@0.8.0": version "0.8.0" resolved "https://registry.yarnpkg.com/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz#33bf4b7b39c178821606f669bbc447a6a629786b" @@ -321,54 +357,94 @@ dependencies: eslint-visitor-keys "^3.3.0" -"@eslint-community/regexpp@^4.5.1": - version "4.11.1" - resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.11.1.tgz#a547badfc719eb3e5f4b556325e542fbe9d7a18f" - integrity sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q== +"@eslint-community/regexpp@^4.10.0", "@eslint-community/regexpp@^4.12.1": + version "4.12.1" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.12.1.tgz#cfc6cffe39df390a3841cde2abccf92eaa7ae0e0" + integrity sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ== -"@eslint-community/regexpp@^4.6.1": - version "4.6.2" - resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.6.2.tgz#1816b5f6948029c5eaacb0703b850ee0cb37d8f8" - integrity sha512-pPTNuaAG3QMH+buKyBIGJs3g/S5y0caxw0ygM3YyE6yJFySwiGGSzA+mM3KJ8QQvzeLh3blwgSonkFjgQdxzMw== +"@eslint/config-array@^0.19.0": + version "0.19.2" + resolved "https://registry.yarnpkg.com/@eslint/config-array/-/config-array-0.19.2.tgz#3060b809e111abfc97adb0bb1172778b90cb46aa" + integrity sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w== + dependencies: + "@eslint/object-schema" "^2.1.6" + debug "^4.3.1" + minimatch "^3.1.2" -"@eslint/eslintrc@^2.1.2": - version "2.1.2" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.2.tgz#c6936b4b328c64496692f76944e755738be62396" - integrity sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g== +"@eslint/core@^0.10.0": + version "0.10.0" + resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.10.0.tgz#23727063c21b335f752dbb3a16450f6f9cbc9091" + integrity sha512-gFHJ+xBOo4G3WRlR1e/3G8A6/KZAH6zcE/hkLRCZTi/B9avAG365QhFA8uOGzTMqgTghpn7/fSnscW++dpMSAw== + dependencies: + "@types/json-schema" "^7.0.15" + +"@eslint/core@^0.11.0": + version "0.11.0" + resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.11.0.tgz#7a9226e850922e42cbd2ba71361eacbe74352a12" + integrity sha512-DWUB2pksgNEb6Bz2fggIy1wh6fGgZP4Xyy/Mt0QZPiloKKXerbqq9D3SBQTlCRYOrcRPu4vuz+CGjwdfqxnoWA== + dependencies: + "@types/json-schema" "^7.0.15" + +"@eslint/eslintrc@^3.2.0": + version "3.2.0" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.2.0.tgz#57470ac4e2e283a6bf76044d63281196e370542c" + integrity sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w== dependencies: ajv "^6.12.4" debug "^4.3.2" - espree "^9.6.0" - globals "^13.19.0" + espree "^10.0.1" + globals "^14.0.0" ignore "^5.2.0" import-fresh "^3.2.1" js-yaml "^4.1.0" minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@eslint/js@8.50.0": - version "8.50.0" - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.50.0.tgz#9e93b850f0f3fa35f5fa59adfd03adae8488e484" - integrity sha512-NCC3zz2+nvYd+Ckfh87rA47zfu2QsQpvc6k1yzTk+b9KzRj0wkGa8LSoGOXN6Zv4lRf/EIoZ80biDh9HOI+RNQ== +"@eslint/js@9.20.0": + version "9.20.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.20.0.tgz#7421bcbe74889fcd65d1be59f00130c289856eb4" + integrity sha512-iZA07H9io9Wn836aVTytRaNqh00Sad+EamwOVJT12GTLw1VGMFV/4JaME+JjLtr9fiGaoWgYnS54wrfWsSs4oQ== + +"@eslint/object-schema@^2.1.6": + version "2.1.6" + resolved "https://registry.yarnpkg.com/@eslint/object-schema/-/object-schema-2.1.6.tgz#58369ab5b5b3ca117880c0f6c0b0f32f6950f24f" + integrity sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA== -"@humanwhocodes/config-array@^0.11.11": - version "0.11.11" - resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.11.tgz#88a04c570dbbc7dd943e4712429c3df09bc32844" - integrity sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA== +"@eslint/plugin-kit@^0.2.5": + version "0.2.5" + resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.2.5.tgz#ee07372035539e7847ef834e3f5e7b79f09e3a81" + integrity sha512-lB05FkqEdUg2AA0xEbUz0SnkXT1LcCTa438W4IWTUh4hdOnVbQyOJ81OrDXsJk/LSiJHubgGEFoR5EHq1NsH1A== dependencies: - "@humanwhocodes/object-schema" "^1.2.1" - debug "^4.1.1" - minimatch "^3.0.5" + "@eslint/core" "^0.10.0" + levn "^0.4.1" + +"@humanfs/core@^0.19.1": + version "0.19.1" + resolved "https://registry.yarnpkg.com/@humanfs/core/-/core-0.19.1.tgz#17c55ca7d426733fe3c561906b8173c336b40a77" + integrity sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA== + +"@humanfs/node@^0.16.6": + version "0.16.6" + resolved "https://registry.yarnpkg.com/@humanfs/node/-/node-0.16.6.tgz#ee2a10eaabd1131987bf0488fd9b820174cd765e" + integrity sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw== + dependencies: + "@humanfs/core" "^0.19.1" + "@humanwhocodes/retry" "^0.3.0" "@humanwhocodes/module-importer@^1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== -"@humanwhocodes/object-schema@^1.2.1": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45" - integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== +"@humanwhocodes/retry@^0.3.0": + version "0.3.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.3.1.tgz#c72a5c76a9fbaf3488e231b13dc52c0da7bab42a" + integrity sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA== + +"@humanwhocodes/retry@^0.4.1": + version "0.4.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.4.1.tgz#9a96ce501bc62df46c4031fbd970e3cc6b10f07b" + integrity sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA== "@istanbuljs/load-nyc-config@^1.0.0": version "1.1.0" @@ -630,7 +706,7 @@ resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== -"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": +"@nodelib/fs.walk@^1.2.3": version "1.2.8" resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== @@ -638,23 +714,21 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@pkgr/utils@^2.4.2": - version "2.4.2" - resolved "https://registry.yarnpkg.com/@pkgr/utils/-/utils-2.4.2.tgz#9e638bbe9a6a6f165580dc943f138fd3309a2cbc" - integrity sha512-POgTXhjrTfbTV63DiFXav4lBHiICLKKwDeaKn9Nphwj7WH6m0hMMCaJkMyRWjgtPFyRKRVoMXXjczsTQRDEhYw== - dependencies: - cross-spawn "^7.0.3" - fast-glob "^3.3.0" - is-glob "^4.0.3" - open "^9.1.0" - picocolors "^1.0.0" - tslib "^2.6.0" +"@pkgr/core@^0.1.0": + version "0.1.1" + resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.1.1.tgz#1ec17e2edbec25c8306d424ecfbf13c7de1aaa31" + integrity sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA== "@sinclair/typebox@^0.27.8": version "0.27.8" resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA== +"@sindresorhus/is@^4.6.0": + version "4.6.0" + resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-4.6.0.tgz#3c7c9c46e678feefe7a2e5bb609d3dbd665ffb3f" + integrity sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw== + "@sinonjs/commons@^3.0.0": version "3.0.0" resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-3.0.0.tgz#beb434fe875d965265e04722ccfc21df7f755d72" @@ -812,6 +886,11 @@ dependencies: "@babel/types" "^7.20.7" +"@types/estree@^1.0.6": + version "1.0.6" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.6.tgz#628effeeae2064a1b4e79f78e81d87b7e5fc7b50" + integrity sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw== + "@types/graceful-fs@^4.1.3": version "4.1.9" resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.9.tgz#2a06bc0f68a20ab37b3e36aa238be6abdf49e8b4" @@ -846,19 +925,11 @@ expect "^29.0.0" pretty-format "^29.0.0" -"@types/json-schema@^7.0.12": +"@types/json-schema@^7.0.15": version "7.0.15" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== -"@types/node-fetch@^2.6.4": - version "2.6.4" - resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.4.tgz#1bc3a26de814f6bf466b25aeb1473fa1afe6a660" - integrity sha512-1ZX9fcN4Rvkvgv4E6PAY5WXUFWFcRWxZa3EW83UjycOB9ljJCedb2CupIP4RZMEwF/M3eTcCihbBRgwtGbg5Rg== - dependencies: - "@types/node" "*" - form-data "^3.0.0" - "@types/node@*": version "20.10.5" resolved "https://registry.yarnpkg.com/@types/node/-/node-20.10.5.tgz#47ad460b514096b7ed63a1dae26fad0914ed3ab2" @@ -866,21 +937,25 @@ dependencies: undici-types "~5.26.4" -"@types/node@^18.11.18": - version "18.11.18" - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.11.18.tgz#8dfb97f0da23c2293e554c5a50d61ef134d7697f" - integrity sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA== - -"@types/semver@^7.5.0": - version "7.5.8" - resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.8.tgz#8268a8c57a3e4abd25c165ecd36237db7948a55e" - integrity sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ== +"@types/node@^20.17.6": + version "20.17.6" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.17.6.tgz#6e4073230c180d3579e8c60141f99efdf5df0081" + integrity sha512-VEI7OdvK2wP7XHnsuXbAJnEpEkF6NjSN45QJlL4VGqZSXsnicpesdTWsg9RISeSdYd3yeRj/y3k5KGjUXYnFwQ== + dependencies: + undici-types "~6.19.2" "@types/stack-utils@^2.0.0": version "2.0.3" resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.3.tgz#6209321eb2c1712a7e7466422b8cb1fc0d9dd5d8" integrity sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw== +"@types/ws@^8.5.13": + version "8.5.14" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.14.tgz#93d44b268c9127d96026cf44353725dd9b6c3c21" + integrity sha512-bd/YFLW+URhBzMXurx7lWByOu+xzU9+kb3RboOteXYDfW+tr+JZa99OyNmPINEGB/ahzKrEuc8rcv4gnpJmxTw== + dependencies: + "@types/node" "*" + "@types/yargs-parser@*": version "21.0.3" resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.3.tgz#815e30b786d2e8f0dcd85fd5bcf5e1a04d008f15" @@ -893,98 +968,86 @@ dependencies: "@types/yargs-parser" "*" -"@typescript-eslint/eslint-plugin@^6.7.0": - version "6.21.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz#30830c1ca81fd5f3c2714e524c4303e0194f9cd3" - integrity sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA== +"@typescript-eslint/eslint-plugin@8.24.0", "@typescript-eslint/eslint-plugin@^8.24.0": + version "8.24.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.24.0.tgz#574a95d67660a1e4544ae131d672867a5b40abb3" + integrity sha512-aFcXEJJCI4gUdXgoo/j9udUYIHgF23MFkg09LFz2dzEmU0+1Plk4rQWv/IYKvPHAtlkkGoB3m5e6oUp+JPsNaQ== dependencies: - "@eslint-community/regexpp" "^4.5.1" - "@typescript-eslint/scope-manager" "6.21.0" - "@typescript-eslint/type-utils" "6.21.0" - "@typescript-eslint/utils" "6.21.0" - "@typescript-eslint/visitor-keys" "6.21.0" - debug "^4.3.4" + "@eslint-community/regexpp" "^4.10.0" + "@typescript-eslint/scope-manager" "8.24.0" + "@typescript-eslint/type-utils" "8.24.0" + "@typescript-eslint/utils" "8.24.0" + "@typescript-eslint/visitor-keys" "8.24.0" graphemer "^1.4.0" - ignore "^5.2.4" + ignore "^5.3.1" natural-compare "^1.4.0" - semver "^7.5.4" - ts-api-utils "^1.0.1" + ts-api-utils "^2.0.1" -"@typescript-eslint/parser@^6.7.0": - version "6.21.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.21.0.tgz#af8fcf66feee2edc86bc5d1cf45e33b0630bf35b" - integrity sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ== +"@typescript-eslint/parser@8.24.0", "@typescript-eslint/parser@^8.24.0": + version "8.24.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.24.0.tgz#bba837f9ee125b78f459ad947ff9b61be8139085" + integrity sha512-MFDaO9CYiard9j9VepMNa9MTcqVvSny2N4hkY6roquzj8pdCBRENhErrteaQuu7Yjn1ppk0v1/ZF9CG3KIlrTA== dependencies: - "@typescript-eslint/scope-manager" "6.21.0" - "@typescript-eslint/types" "6.21.0" - "@typescript-eslint/typescript-estree" "6.21.0" - "@typescript-eslint/visitor-keys" "6.21.0" + "@typescript-eslint/scope-manager" "8.24.0" + "@typescript-eslint/types" "8.24.0" + "@typescript-eslint/typescript-estree" "8.24.0" + "@typescript-eslint/visitor-keys" "8.24.0" debug "^4.3.4" -"@typescript-eslint/scope-manager@6.21.0": - version "6.21.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz#ea8a9bfc8f1504a6ac5d59a6df308d3a0630a2b1" - integrity sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg== +"@typescript-eslint/scope-manager@8.24.0": + version "8.24.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.24.0.tgz#2e34b3eb2ce768f2ffb109474174ced5417002b1" + integrity sha512-HZIX0UByphEtdVBKaQBgTDdn9z16l4aTUz8e8zPQnyxwHBtf5vtl1L+OhH+m1FGV9DrRmoDuYKqzVrvWDcDozw== dependencies: - "@typescript-eslint/types" "6.21.0" - "@typescript-eslint/visitor-keys" "6.21.0" + "@typescript-eslint/types" "8.24.0" + "@typescript-eslint/visitor-keys" "8.24.0" -"@typescript-eslint/type-utils@6.21.0": - version "6.21.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz#6473281cfed4dacabe8004e8521cee0bd9d4c01e" - integrity sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag== +"@typescript-eslint/type-utils@8.24.0": + version "8.24.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.24.0.tgz#6ee3ec4db06f9e5e7b01ca6c2b5dd5843a9fd1e8" + integrity sha512-8fitJudrnY8aq0F1wMiPM1UUgiXQRJ5i8tFjq9kGfRajU+dbPyOuHbl0qRopLEidy0MwqgTHDt6CnSeXanNIwA== dependencies: - "@typescript-eslint/typescript-estree" "6.21.0" - "@typescript-eslint/utils" "6.21.0" + "@typescript-eslint/typescript-estree" "8.24.0" + "@typescript-eslint/utils" "8.24.0" debug "^4.3.4" - ts-api-utils "^1.0.1" + ts-api-utils "^2.0.1" -"@typescript-eslint/types@6.21.0": - version "6.21.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.21.0.tgz#205724c5123a8fef7ecd195075fa6e85bac3436d" - integrity sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg== +"@typescript-eslint/types@8.24.0": + version "8.24.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.24.0.tgz#694e7fb18d70506c317b816de9521300b0f72c8e" + integrity sha512-VacJCBTyje7HGAw7xp11q439A+zeGG0p0/p2zsZwpnMzjPB5WteaWqt4g2iysgGFafrqvyLWqq6ZPZAOCoefCw== -"@typescript-eslint/typescript-estree@6.21.0": - version "6.21.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz#c47ae7901db3b8bddc3ecd73daff2d0895688c46" - integrity sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ== +"@typescript-eslint/typescript-estree@8.24.0": + version "8.24.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.24.0.tgz#0487349be174097bb329a58273100a9629e03c6c" + integrity sha512-ITjYcP0+8kbsvT9bysygfIfb+hBj6koDsu37JZG7xrCiy3fPJyNmfVtaGsgTUSEuTzcvME5YI5uyL5LD1EV5ZQ== dependencies: - "@typescript-eslint/types" "6.21.0" - "@typescript-eslint/visitor-keys" "6.21.0" + "@typescript-eslint/types" "8.24.0" + "@typescript-eslint/visitor-keys" "8.24.0" debug "^4.3.4" - globby "^11.1.0" + fast-glob "^3.3.2" is-glob "^4.0.3" - minimatch "9.0.3" - semver "^7.5.4" - ts-api-utils "^1.0.1" + minimatch "^9.0.4" + semver "^7.6.0" + ts-api-utils "^2.0.1" -"@typescript-eslint/utils@6.21.0": - version "6.21.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.21.0.tgz#4714e7a6b39e773c1c8e97ec587f520840cd8134" - integrity sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ== +"@typescript-eslint/utils@8.24.0": + version "8.24.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.24.0.tgz#21cb1195ae79230af825bfeed59574f5cb70a749" + integrity sha512-07rLuUBElvvEb1ICnafYWr4hk8/U7X9RDCOqd9JcAMtjh/9oRmcfN4yGzbPVirgMR0+HLVHehmu19CWeh7fsmQ== dependencies: "@eslint-community/eslint-utils" "^4.4.0" - "@types/json-schema" "^7.0.12" - "@types/semver" "^7.5.0" - "@typescript-eslint/scope-manager" "6.21.0" - "@typescript-eslint/types" "6.21.0" - "@typescript-eslint/typescript-estree" "6.21.0" - semver "^7.5.4" - -"@typescript-eslint/visitor-keys@6.21.0": - version "6.21.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz#87a99d077aa507e20e238b11d56cc26ade45fe47" - integrity sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A== - dependencies: - "@typescript-eslint/types" "6.21.0" - eslint-visitor-keys "^3.4.1" + "@typescript-eslint/scope-manager" "8.24.0" + "@typescript-eslint/types" "8.24.0" + "@typescript-eslint/typescript-estree" "8.24.0" -abort-controller@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/abort-controller/-/abort-controller-3.0.0.tgz#eaf54d53b62bae4138e809ca225c8439a6efb392" - integrity sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg== +"@typescript-eslint/visitor-keys@8.24.0": + version "8.24.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.24.0.tgz#36ecf0b9b1d819ad88a3bd4157ab7d594cb797c9" + integrity sha512-kArLq83QxGLbuHrTMoOEWO+l2MwsNS2TGISEdx8xgqpkbytB07XmlQyQdNDrCc1ecSqx0cnmhGvpX+VBwqqSkg== dependencies: - event-target-shim "^5.0.0" + "@typescript-eslint/types" "8.24.0" + eslint-visitor-keys "^4.2.0" acorn-jsx@^5.3.2: version "5.3.2" @@ -996,25 +1059,16 @@ acorn-walk@^8.1.1: resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== +acorn@^8.14.0: + version "8.14.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.0.tgz#063e2c70cac5fb4f6467f0b11152e04c682795b0" + integrity sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA== + acorn@^8.4.1: version "8.7.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.0.tgz#90951fde0f8f09df93549481e5fc141445b791cf" integrity sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ== -acorn@^8.9.0: - version "8.10.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.10.0.tgz#8be5b3907a67221a81ab23c7889c4c5526b62ec5" - integrity sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw== - -agentkeepalive@^4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.2.1.tgz#a7975cbb9f83b367f06c90cc51ff28fe7d499717" - integrity sha512-Zn4cw2NEqd+9fiSVWMscnjyQ1a8Yfoc5oBajLeo5w+YBHgDUcEBY2hS4YpTz6iN5f/2zQiktcuM6tS8x1p9dpA== - dependencies: - debug "^4.1.0" - depd "^1.1.2" - humanize-ms "^1.2.1" - aggregate-error@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" @@ -1040,11 +1094,23 @@ ansi-escapes@^4.2.1: dependencies: type-fest "^0.21.3" +ansi-escapes@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-7.0.0.tgz#00fc19f491bbb18e1d481b97868204f92109bfe7" + integrity sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw== + dependencies: + environment "^1.0.0" + ansi-regex@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== +ansi-regex@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.1.0.tgz#95ec409c69619d6cb1b8b34f14b660ef28ebd654" + integrity sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA== + ansi-styles@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" @@ -1064,6 +1130,11 @@ ansi-styles@^5.0.0: resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== +any-promise@^1.0.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" + integrity sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A== + anymatch@^3.0.3: version "3.1.3" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" @@ -1089,16 +1160,6 @@ argparse@^2.0.1: resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== -array-union@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" - integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== - -asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= - babel-jest@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.7.0.tgz#f4369919225b684c56085998ac63dbd05be020d5" @@ -1164,25 +1225,6 @@ balanced-match@^1.0.0: resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== -big-integer@^1.6.44: - version "1.6.52" - resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.52.tgz#60a887f3047614a8e1bffe5d7173490a97dc8c85" - integrity sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg== - -bindings@^1.2.1: - version "1.5.0" - resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" - integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== - dependencies: - file-uri-to-path "1.0.0" - -bplist-parser@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/bplist-parser/-/bplist-parser-0.2.0.tgz#43a9d183e5bf9d545200ceac3e712f79ebbe8d0e" - integrity sha512-z0M+byMThzQmD9NILRniCUXYsYpjwnlO8N5uCFaCqIOpqRsJCrQL9NK3JsD67CN5a08nF5oIL2bD6loTdHOuKw== - dependencies: - big-integer "^1.6.44" - brace-expansion@^1.1.7: version "1.1.11" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" @@ -1234,13 +1276,6 @@ buffer-from@^1.0.0: resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== -bundle-name@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/bundle-name/-/bundle-name-3.0.0.tgz#ba59bcc9ac785fb67ccdbf104a2bf60c099f0e1a" - integrity sha512-PKA4BeSvBpQKQ8iPOGCSiell+N8P+Tf1DlwqmYhpe2gAhKPHn8EYOxVT+ShuGmhg8lN8XiSlS80yiExKXrURlw== - dependencies: - run-applescript "^5.0.0" - callsites@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" @@ -1270,7 +1305,7 @@ chalk@^2.4.2: escape-string-regexp "^1.0.5" supports-color "^5.3.0" -chalk@^4.0.0: +chalk@^4.0.0, chalk@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== @@ -1278,6 +1313,11 @@ chalk@^4.0.0: ansi-styles "^4.1.0" supports-color "^7.1.0" +chalk@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.3.0.tgz#67c20a7ebef70e7f3970a01f90fa210cb6860385" + integrity sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w== + char-regex@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" @@ -1293,11 +1333,46 @@ cjs-module-lexer@^1.0.0: resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz#6c370ab19f8a3394e318fe682686ec0ac684d107" integrity sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ== +cjs-module-lexer@^1.2.3: + version "1.4.1" + resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.4.1.tgz#707413784dbb3a72aa11c2f2b042a0bef4004170" + integrity sha512-cuSVIHi9/9E/+821Qjdvngor+xpnlwnuwIyZOaLmHBVdXL+gP+I6QQB9VkO7RI77YIcTV+S1W9AreJ5eN63JBA== + clean-stack@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== +cli-highlight@^2.1.11: + version "2.1.11" + resolved "https://registry.yarnpkg.com/cli-highlight/-/cli-highlight-2.1.11.tgz#49736fa452f0aaf4fae580e30acb26828d2dc1bf" + integrity sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg== + dependencies: + chalk "^4.0.0" + highlight.js "^10.7.1" + mz "^2.4.0" + parse5 "^5.1.1" + parse5-htmlparser2-tree-adapter "^6.0.0" + yargs "^16.0.0" + +cli-table3@^0.6.3, cli-table3@^0.6.5: + version "0.6.5" + resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.6.5.tgz#013b91351762739c16a9567c21a04632e449bf2f" + integrity sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ== + dependencies: + string-width "^4.2.0" + optionalDependencies: + "@colors/colors" "1.5.0" + +cliui@^7.0.2: + version "7.0.4" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + cliui@^8.0.1: version "8.0.1" resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" @@ -1341,12 +1416,10 @@ color-name@~1.1.4: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== -combined-stream@^1.0.8: - version "1.0.8" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" - integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== - dependencies: - delayed-stream "~1.0.0" +commander@^10.0.1: + version "10.0.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06" + integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug== concat-map@0.0.1: version "0.0.1" @@ -1376,7 +1449,7 @@ create-require@^1.1.0: resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== -cross-spawn@^7.0.2, cross-spawn@^7.0.3: +cross-spawn@^7.0.3, cross-spawn@^7.0.6: version "7.0.6" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== @@ -1392,7 +1465,7 @@ debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2: dependencies: ms "2.1.2" -debug@^4.3.4: +debug@^4.3.4, debug@^4.3.7: version "4.3.7" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52" integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ== @@ -1414,39 +1487,6 @@ deepmerge@^4.2.2: resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== -default-browser-id@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/default-browser-id/-/default-browser-id-3.0.0.tgz#bee7bbbef1f4e75d31f98f4d3f1556a14cea790c" - integrity sha512-OZ1y3y0SqSICtE8DE4S8YOE9UZOJ8wO16fKWVP5J1Qz42kV9jcnMVFrEE/noXb/ss3Q4pZIH79kxofzyNNtUNA== - dependencies: - bplist-parser "^0.2.0" - untildify "^4.0.0" - -default-browser@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/default-browser/-/default-browser-4.0.0.tgz#53c9894f8810bf86696de117a6ce9085a3cbc7da" - integrity sha512-wX5pXO1+BrhMkSbROFsyxUm0i/cJEScyNhA4PPxc41ICuv05ZZB/MX28s8aZx6xjmatvebIapF6hLEKEcpneUA== - dependencies: - bundle-name "^3.0.0" - default-browser-id "^3.0.0" - execa "^7.1.1" - titleize "^3.0.0" - -define-lazy-prop@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz#dbb19adfb746d7fc6d734a06b72f4a00d021255f" - integrity sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg== - -delayed-stream@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= - -depd@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" - integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= - detect-newline@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" @@ -1462,20 +1502,6 @@ diff@^4.0.1: resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== -dir-glob@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" - integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== - dependencies: - path-type "^4.0.0" - -doctrine@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" - integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== - dependencies: - esutils "^2.0.2" - electron-to-chromium@^1.4.601: version "1.4.614" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.614.tgz#2fe789d61fa09cb875569f37c309d0c2701f91c0" @@ -1491,6 +1517,16 @@ emoji-regex@^8.0.0: resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== +emojilib@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/emojilib/-/emojilib-2.4.0.tgz#ac518a8bb0d5f76dda57289ccb2fdf9d39ae721e" + integrity sha512-5U0rVMU5Y2n2+ykNLQqMoqklN9ICBT/KsvC1Gz6vqHbz2AXXGkG+Pm5rMWk/8Vjrr/mY9985Hi8DYzn1F09Nyw== + +environment@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/environment/-/environment-1.1.0.tgz#8e86c66b180f363c7ab311787e0259665f45a9f1" + integrity sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q== + error-ex@^1.3.1: version "1.3.2" resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" @@ -1518,100 +1554,95 @@ escape-string-regexp@^4.0.0: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== -eslint-plugin-prettier@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.0.1.tgz#a3b399f04378f79f066379f544e42d6b73f11515" - integrity sha512-m3u5RnR56asrwV/lDC4GHorlW75DsFfmUcjfCYylTUs85dBRnB7VM6xG8eCMJdeDRnppzmxZVf1GEPJvl1JmNg== +eslint-plugin-prettier@^5.2.3: + version "5.2.3" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.3.tgz#c4af01691a6fa9905207f0fbba0d7bea0902cce5" + integrity sha512-qJ+y0FfCp/mQYQ/vWQ3s7eUlFEL4PyKfAJxsnYTJ4YT73nsJBWqmEpFryxV9OeUiqmsTsYJ5Y+KDNaeP31wrRw== dependencies: prettier-linter-helpers "^1.0.0" - synckit "^0.8.5" + synckit "^0.9.1" -eslint-plugin-unused-imports@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-3.0.0.tgz#d25175b0072ff16a91892c3aa72a09ca3a9e69e7" - integrity sha512-sduiswLJfZHeeBJ+MQaG+xYzSWdRXoSw61DpU13mzWumCkR0ufD0HmO4kdNokjrkluMHpj/7PJeN35pgbhW3kw== - dependencies: - eslint-rule-composer "^0.3.0" - -eslint-rule-composer@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz#79320c927b0c5c0d3d3d2b76c8b4a488f25bbaf9" - integrity sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg== +eslint-plugin-unused-imports@^4.1.4: + version "4.1.4" + resolved "https://registry.yarnpkg.com/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-4.1.4.tgz#62ddc7446ccbf9aa7b6f1f0b00a980423cda2738" + integrity sha512-YptD6IzQjDardkl0POxnnRBhU1OEePMV0nd6siHaRBbd+lyh6NAhFEobiznKU7kTsSsDeSD62Pe7kAM1b7dAZQ== -eslint-scope@^7.2.2: - version "7.2.2" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f" - integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== +eslint-scope@^8.2.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-8.2.0.tgz#377aa6f1cb5dc7592cfd0b7f892fd0cf352ce442" + integrity sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A== dependencies: esrecurse "^4.3.0" estraverse "^5.2.0" -eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: +eslint-visitor-keys@^3.3.0: version "3.4.3" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== -eslint@^8.49.0: - version "8.50.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.50.0.tgz#2ae6015fee0240fcd3f83e1e25df0287f487d6b2" - integrity sha512-FOnOGSuFuFLv/Sa+FDVRZl4GGVAAFFi8LecRsI5a1tMO5HIE8nCm4ivAlzt4dT3ol/PaaGC0rJEEXQmHJBGoOg== +eslint-visitor-keys@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz#687bacb2af884fcdda8a6e7d65c606f46a14cd45" + integrity sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw== + +eslint@^9.20.1: + version "9.20.1" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.20.1.tgz#923924c078f5226832449bac86662dd7e53c91d6" + integrity sha512-m1mM33o6dBUjxl2qb6wv6nGNwCAsns1eKtaQ4l/NPHeTvhiUPbtdfMyktxN4B3fgHIgsYh1VT3V9txblpQHq+g== dependencies: "@eslint-community/eslint-utils" "^4.2.0" - "@eslint-community/regexpp" "^4.6.1" - "@eslint/eslintrc" "^2.1.2" - "@eslint/js" "8.50.0" - "@humanwhocodes/config-array" "^0.11.11" + "@eslint-community/regexpp" "^4.12.1" + "@eslint/config-array" "^0.19.0" + "@eslint/core" "^0.11.0" + "@eslint/eslintrc" "^3.2.0" + "@eslint/js" "9.20.0" + "@eslint/plugin-kit" "^0.2.5" + "@humanfs/node" "^0.16.6" "@humanwhocodes/module-importer" "^1.0.1" - "@nodelib/fs.walk" "^1.2.8" + "@humanwhocodes/retry" "^0.4.1" + "@types/estree" "^1.0.6" + "@types/json-schema" "^7.0.15" ajv "^6.12.4" chalk "^4.0.0" - cross-spawn "^7.0.2" + cross-spawn "^7.0.6" debug "^4.3.2" - 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.4.2" + eslint-scope "^8.2.0" + eslint-visitor-keys "^4.2.0" + espree "^10.3.0" + esquery "^1.5.0" esutils "^2.0.2" fast-deep-equal "^3.1.3" - file-entry-cache "^6.0.1" + file-entry-cache "^8.0.0" find-up "^5.0.0" glob-parent "^6.0.2" - globals "^13.19.0" - graphemer "^1.4.0" ignore "^5.2.0" imurmurhash "^0.1.4" is-glob "^4.0.0" - 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.3" - strip-ansi "^6.0.1" - text-table "^0.2.0" -espree@^9.6.0, espree@^9.6.1: - version "9.6.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" - integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== +espree@^10.0.1, espree@^10.3.0: + version "10.3.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-10.3.0.tgz#29267cf5b0cb98735b65e64ba07e0ed49d1eed8a" + integrity sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg== dependencies: - acorn "^8.9.0" + acorn "^8.14.0" acorn-jsx "^5.3.2" - eslint-visitor-keys "^3.4.1" + eslint-visitor-keys "^4.2.0" esprima@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== -esquery@^1.4.2: - version "1.5.0" - resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.5.0.tgz#6ce17738de8577694edd7361c57182ac8cb0db0b" - integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== +esquery@^1.5.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7" + integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg== dependencies: estraverse "^5.1.0" @@ -1632,12 +1663,7 @@ esutils@^2.0.2: resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== -event-target-shim@^5.0.0: - version "5.0.1" - resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" - integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== - -execa@^5.0.0: +execa@^5.0.0, execa@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== @@ -1652,21 +1678,6 @@ execa@^5.0.0: signal-exit "^3.0.3" strip-final-newline "^2.0.0" -execa@^7.1.1: - version "7.2.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-7.2.0.tgz#657e75ba984f42a70f38928cedc87d6f2d4fe4e9" - integrity sha512-UduyVP7TLB5IcAQl+OzLyLcS/l32W/GLg+AhHJ+ow40FOk2U3SAllPwR44v4vmdFwIWqpdwxxpQbF1n5ta9seA== - dependencies: - cross-spawn "^7.0.3" - get-stream "^6.0.1" - human-signals "^4.3.0" - is-stream "^3.0.0" - merge-stream "^2.0.0" - npm-run-path "^5.1.0" - onetime "^6.0.0" - signal-exit "^3.0.7" - strip-final-newline "^3.0.0" - exit@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" @@ -1684,9 +1695,9 @@ expect@^29.0.0, expect@^29.7.0: jest-util "^29.7.0" fast-check@^3.22.0: - version "3.22.0" - resolved "https://registry.yarnpkg.com/fast-check/-/fast-check-3.22.0.tgz#1a8153e9d6fbdcc60b818f447cbb9cac1fdd8fb6" - integrity sha512-8HKz3qXqnHYp/VCNn2qfjHdAdcI8zcSqOyX64GOMukp7SL2bfzfeDKjSd+UyECtejccaZv3LcvZTm9YDD22iCQ== + version "3.23.2" + resolved "https://registry.yarnpkg.com/fast-check/-/fast-check-3.23.2.tgz#0129f1eb7e4f500f58e8290edc83c670e4a574a2" + integrity sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A== dependencies: pure-rand "^6.1.0" @@ -1700,18 +1711,7 @@ fast-diff@^1.1.2: resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.3.0.tgz#ece407fa550a64d638536cd727e129c61616e0f0" integrity sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw== -fast-glob@^3.2.12: - version "3.2.12" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.12.tgz#7f39ec99c2e6ab030337142da9e0c18f37afae80" - integrity sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w== - dependencies: - "@nodelib/fs.stat" "^2.0.2" - "@nodelib/fs.walk" "^1.2.3" - glob-parent "^5.1.2" - merge2 "^1.3.0" - micromatch "^4.0.4" - -fast-glob@^3.2.9, fast-glob@^3.3.0: +fast-glob@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== @@ -1746,17 +1746,17 @@ fb-watchman@^2.0.0: dependencies: bser "2.1.1" -file-entry-cache@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" - integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== - dependencies: - flat-cache "^3.0.4" +fflate@^0.8.2: + version "0.8.2" + resolved "https://registry.yarnpkg.com/fflate/-/fflate-0.8.2.tgz#fc8631f5347812ad6028bbe4a2308b2792aa1dea" + integrity sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A== -file-uri-to-path@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" - integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== +file-entry-cache@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-8.0.0.tgz#7787bddcf1131bffb92636c69457bbc0edd6d81f" + integrity sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ== + dependencies: + flat-cache "^4.0.0" fill-range@^7.1.1: version "7.1.1" @@ -1781,40 +1781,18 @@ find-up@^5.0.0: locate-path "^6.0.0" path-exists "^4.0.0" -flat-cache@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.0.4.tgz#61b0338302b2fe9f957dcc32fc2a87f1c3048b11" - integrity sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg== - dependencies: - flatted "^3.1.0" - rimraf "^3.0.2" - -flatted@^3.1.0: - version "3.2.7" - resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.7.tgz#609f39207cb614b89d0765b477cb2d437fbf9787" - integrity sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ== - -form-data-encoder@1.7.2: - version "1.7.2" - resolved "https://registry.yarnpkg.com/form-data-encoder/-/form-data-encoder-1.7.2.tgz#1f1ae3dccf58ed4690b86d87e4f57c654fbab040" - integrity sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A== - -form-data@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f" - integrity sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg== +flat-cache@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-4.0.1.tgz#0ece39fcb14ee012f4b0410bd33dd9c1f011127c" + integrity sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw== dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.8" - mime-types "^2.1.12" + flatted "^3.2.9" + keyv "^4.5.4" -formdata-node@^4.3.2: - version "4.3.3" - resolved "https://registry.yarnpkg.com/formdata-node/-/formdata-node-4.3.3.tgz#21415225be66e2c87a917bfc0fedab30a119c23c" - integrity sha512-coTew7WODO2vF+XhpUdmYz4UBvlsiTMSNaFYZlrXIqYbFd4W7bMwnoALNLE6uvNgzTg2j1JDF0ZImEfF06VPAA== - dependencies: - node-domexception "1.0.0" - web-streams-polyfill "4.0.0-beta.1" +flatted@^3.2.9: + version "3.3.2" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.2.tgz#adba1448a9841bec72b42c532ea23dbbedef1a27" + integrity sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA== fs.realpath@^1.0.0: version "1.0.0" @@ -1851,7 +1829,7 @@ get-stdin@^8.0.0: resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-8.0.0.tgz#cbad6a73feb75f6eeb22ba9e01f89aa28aa97a53" integrity sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg== -get-stream@^6.0.0, get-stream@^6.0.1: +get-stream@^6.0.0: version "6.0.1" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== @@ -1882,29 +1860,26 @@ glob@^7.1.3, glob@^7.1.4: once "^1.3.0" path-is-absolute "^1.0.0" +glob@^8.0.1: + version "8.1.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-8.1.0.tgz#d388f656593ef708ee3e34640fdfb99a9fd1c33e" + integrity sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^5.0.1" + once "^1.3.0" + globals@^11.1.0: version "11.12.0" resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== -globals@^13.19.0: - version "13.20.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-13.20.0.tgz#ea276a1e508ffd4f1612888f9d1bad1e2717bf82" - integrity sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ== - dependencies: - type-fest "^0.20.2" - -globby@^11.1.0: - version "11.1.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" - integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== - dependencies: - array-union "^2.1.0" - dir-glob "^3.0.1" - fast-glob "^3.2.9" - ignore "^5.2.0" - merge2 "^1.4.1" - slash "^3.0.0" +globals@^14.0.0: + version "14.0.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-14.0.0.tgz#898d7413c29babcf6bafe56fcadded858ada724e" + integrity sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ== graceful-fs@^4.2.9: version "4.2.11" @@ -1933,6 +1908,11 @@ hasown@^2.0.0: dependencies: function-bind "^1.1.2" +highlight.js@^10.7.1: + version "10.7.3" + resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.3.tgz#697272e3991356e40c3cac566a74eef681756531" + integrity sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A== + html-escaper@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" @@ -1943,18 +1923,6 @@ human-signals@^2.1.0: resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== -human-signals@^4.3.0: - version "4.3.1" - resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-4.3.1.tgz#ab7f811e851fca97ffbd2c1fe9a958964de321b2" - integrity sha512-nZXjEF2nbo7lIw3mgYjItAfgQXog3OjJogSbKa2CQIIvSGWcKgeJnQlNXip6NglNzYH45nSRiEVimMvYL8DDqQ== - -humanize-ms@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" - integrity sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0= - dependencies: - ms "^2.0.0" - iconv-lite@^0.6.3: version "0.6.3" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" @@ -1962,7 +1930,14 @@ iconv-lite@^0.6.3: dependencies: safer-buffer ">= 2.1.2 < 3.0.0" -ignore@^5.2.0, ignore@^5.2.4: +ignore-walk@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-5.0.1.tgz#5f199e23e1288f518d90358d461387788a154776" + integrity sha512-yemi4pMf51WKT7khInJqAvsIGzoqYXblnsz0ql8tM+yi1EKYTY1evX4NAbJrLL/Aanr2HyZeluqU+Oi7MGHokw== + dependencies: + minimatch "^5.0.1" + +ignore@^5.2.0, ignore@^5.3.1: version "5.3.2" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== @@ -2018,16 +1993,6 @@ is-core-module@^2.13.0: dependencies: hasown "^2.0.0" -is-docker@^2.0.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" - integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== - -is-docker@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-3.0.0.tgz#90093aa3106277d8a77a5910dbae71747e15a200" - integrity sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ== - is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" @@ -2050,40 +2015,16 @@ is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: dependencies: is-extglob "^2.1.1" -is-inside-container@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-inside-container/-/is-inside-container-1.0.0.tgz#e81fba699662eb31dbdaf26766a61d4814717ea4" - integrity sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA== - dependencies: - is-docker "^3.0.0" - is-number@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== -is-path-inside@^3.0.3: - version "3.0.3" - resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" - integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== - is-stream@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== -is-stream@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-3.0.0.tgz#e6bfd7aa6bef69f4f472ce9bb681e3e57b4319ac" - integrity sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA== - -is-wsl@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" - integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== - dependencies: - is-docker "^2.0.0" - isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" @@ -2525,6 +2466,11 @@ jsesc@^2.5.1: resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== +json-buffer@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== + json-parse-even-better-errors@^2.3.0: version "2.3.1" resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" @@ -2550,6 +2496,13 @@ jsonc-parser@^3.2.0: resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.2.1.tgz#031904571ccf929d7670ee8c547545081cb37f1a" integrity sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA== +keyv@^4.5.4: + version "4.5.4" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" + integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== + dependencies: + json-buffer "3.0.1" + kleur@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" @@ -2597,6 +2550,11 @@ lodash.merge@^4.6.2: resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== +lru-cache@^10.4.3: + version "10.4.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" + integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== + lru-cache@^5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" @@ -2630,12 +2588,30 @@ makeerror@1.0.12: dependencies: tmpl "1.0.5" +marked-terminal@^7.1.0: + version "7.2.1" + resolved "https://registry.yarnpkg.com/marked-terminal/-/marked-terminal-7.2.1.tgz#9c1ae073a245a03c6a13e3eeac6f586f29856068" + integrity sha512-rQ1MoMFXZICWNsKMiiHwP/Z+92PLKskTPXj+e7uwXmuMPkNn7iTqC+IvDekVm1MPeC9wYQeLxeFaOvudRR/XbQ== + dependencies: + ansi-escapes "^7.0.0" + ansi-regex "^6.1.0" + chalk "^5.3.0" + cli-highlight "^2.1.11" + cli-table3 "^0.6.5" + node-emoji "^2.1.3" + supports-hyperlinks "^3.1.0" + +marked@^9.1.2: + version "9.1.6" + resolved "https://registry.yarnpkg.com/marked/-/marked-9.1.6.tgz#5d2a3f8180abfbc5d62e3258a38a1c19c0381695" + integrity sha512-jcByLnIFkd5gSXZmjNvS1TlmRhCXZjIzHYlaGkPlLIekG55JDR2Z4va9tZwCiP+/RDERiNhMOFu01xd6O5ct1Q== + merge-stream@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== -merge2@^1.3.0, merge2@^1.4.1: +merge2@^1.3.0: version "1.4.1" resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== @@ -2648,78 +2624,75 @@ micromatch@^4.0.4: braces "^3.0.3" picomatch "^2.3.1" -mime-db@1.51.0: - version "1.51.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.51.0.tgz#d9ff62451859b18342d960850dc3cfb77e63fb0c" - integrity sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g== - -mime-types@^2.1.12: - version "2.1.34" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.34.tgz#5a712f9ec1503511a945803640fafe09d3793c24" - integrity sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A== - dependencies: - mime-db "1.51.0" - mimic-fn@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== -mimic-fn@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-4.0.0.tgz#60a90550d5cb0b239cca65d893b1a53b29871ecc" - integrity sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw== - -minimatch@9.0.3: - version "9.0.3" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" - integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== - dependencies: - brace-expansion "^2.0.1" - -minimatch@^3.0.4, minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: +minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== dependencies: brace-expansion "^1.1.7" +minimatch@^5.0.1: + version "5.1.6" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" + integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== + dependencies: + brace-expansion "^2.0.1" + +minimatch@^9.0.4: + version "9.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== + dependencies: + brace-expansion "^2.0.1" + minimist@^1.2.6: version "1.2.6" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== +mri@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/mri/-/mri-1.2.0.tgz#6721480fec2a11a4889861115a48b6cbe7cc8f0b" + integrity sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA== + ms@2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@^2.0.0, ms@^2.1.3: +ms@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== -nan@^2.14.0: - version "2.22.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.22.0.tgz#31bc433fc33213c97bad36404bb68063de604de3" - integrity sha512-nbajikzWTMwsW+eSsNm3QwlOs7het9gGJU5dDZzRTQGk03vyBOauxgI4VakDzE0PtsGTmXPsXTbbjVhRwR5mpw== +mz@^2.4.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" + integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q== + dependencies: + any-promise "^1.0.0" + object-assign "^4.0.1" + thenify-all "^1.0.0" natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== -node-domexception@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/node-domexception/-/node-domexception-1.0.0.tgz#6888db46a1f71c0b76b3f7555016b63fe64766e5" - integrity sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ== - -node-fetch@^2.6.7: - version "2.6.11" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.11.tgz#cde7fc71deef3131ef80a738919f999e6edfff25" - integrity sha512-4I6pdBY1EthSqDmJkiNk3JIT8cswwR9nfeW/cPdUagJYEQG7R95WRH74wpz7ma8Gh/9dI9FP+OU+0E4FvtA55w== +node-emoji@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/node-emoji/-/node-emoji-2.1.3.tgz#93cfabb5cc7c3653aa52f29d6ffb7927d8047c06" + integrity sha512-E2WEOVsgs7O16zsURJ/eH8BqhF029wGpEOnv7Urwdo2wmQanOACwJQh0devF9D9RhoZru0+9JXIS0dBXIAz+lA== dependencies: - whatwg-url "^5.0.0" + "@sindresorhus/is" "^4.6.0" + char-regex "^1.0.2" + emojilib "^2.4.0" + skin-tone "^2.0.0" node-int64@^0.4.0: version "0.4.0" @@ -2736,6 +2709,28 @@ normalize-path@^3.0.0: resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== +npm-bundled@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-2.0.1.tgz#94113f7eb342cd7a67de1e789f896b04d2c600f4" + integrity sha512-gZLxXdjEzE/+mOstGDqR6b0EkhJ+kM6fxM6vUuckuctuVPh80Q6pw/rSZj9s4Gex9GxWtIicO1pc8DB9KZWudw== + dependencies: + npm-normalize-package-bin "^2.0.0" + +npm-normalize-package-bin@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/npm-normalize-package-bin/-/npm-normalize-package-bin-2.0.0.tgz#9447a1adaaf89d8ad0abe24c6c84ad614a675fff" + integrity sha512-awzfKUO7v0FscrSpRoogyNm0sajikhBWpU0QMrW09AMi9n1PoKU6WaIqUzuJSQnpciZZmJ/jMZ2Egfmb/9LiWQ== + +npm-packlist@^5.1.3: + version "5.1.3" + resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-5.1.3.tgz#69d253e6fd664b9058b85005905012e00e69274b" + integrity sha512-263/0NGrn32YFYi4J533qzrQ/krmmrWwhKkzwTuM4f/07ug51odoaNjUexxO4vxlzURHcmYMH1QjvHjsNDKLVg== + dependencies: + glob "^8.0.1" + ignore-walk "^5.0.1" + npm-bundled "^2.0.0" + npm-normalize-package-bin "^2.0.0" + npm-run-path@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" @@ -2743,12 +2738,10 @@ npm-run-path@^4.0.1: dependencies: path-key "^3.0.0" -npm-run-path@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-5.1.0.tgz#bc62f7f3f6952d9894bd08944ba011a6ee7b7e00" - integrity sha512-sJOdmRGrY2sjNTRMbSvluQqg+8X7ZK61yvzBEIDhz4f8z1TZFYABsqjjCBd/0PUNE9M6QDgHJXQkGUEm7Q+l9Q== - dependencies: - path-key "^4.0.0" +object-assign@^4.0.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== once@^1.3.0: version "1.4.0" @@ -2764,23 +2757,6 @@ onetime@^5.1.2: dependencies: mimic-fn "^2.1.0" -onetime@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-6.0.0.tgz#7c24c18ed1fd2e9bca4bd26806a33613c77d34b4" - integrity sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ== - dependencies: - mimic-fn "^4.0.0" - -open@^9.1.0: - version "9.1.0" - resolved "https://registry.yarnpkg.com/open/-/open-9.1.0.tgz#684934359c90ad25742f5a26151970ff8c6c80b6" - integrity sha512-OS+QTnw1/4vrf+9hh1jc1jnYjzSG4ttTBB8UxOwAnInG3Uo4ssetzC1ihqaIHjLJnA5GGlRl6QlZXOTQhRBUvg== - dependencies: - default-browser "^4.0.0" - define-lazy-prop "^3.0.0" - is-inside-container "^1.0.0" - is-wsl "^2.2.0" - optionator@^0.9.3: version "0.9.3" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.3.tgz#007397d44ed1872fdc6ed31360190f81814e2c64" @@ -2857,6 +2833,23 @@ parse-json@^5.2.0: json-parse-even-better-errors "^2.3.0" lines-and-columns "^1.1.6" +parse5-htmlparser2-tree-adapter@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz#2cdf9ad823321140370d4dbf5d3e92c7c8ddc6e6" + integrity sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA== + dependencies: + parse5 "^6.0.1" + +parse5@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.1.tgz#f68e4e5ba1852ac2cadc00f4555fff6c2abb6178" + integrity sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug== + +parse5@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" + integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== + path-exists@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" @@ -2872,26 +2865,21 @@ path-key@^3.0.0, path-key@^3.1.0: resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== -path-key@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-4.0.0.tgz#295588dc3aee64154f877adb9d780b81c554bf18" - integrity sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ== - path-parse@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== -path-type@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" - integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== - picocolors@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== +picocolors@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" + integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== + picomatch@^2.0.4, picomatch@^2.2.3, picomatch@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" @@ -2914,11 +2902,6 @@ prelude-ls@^1.2.1: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== -"prettier-2@npm:prettier@^2": - version "2.8.8" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da" - integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== - prettier-linter-helpers@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" @@ -2948,6 +2931,15 @@ prompts@^2.0.1: kleur "^3.0.3" sisteransi "^1.0.5" +publint@^0.2.12: + version "0.2.12" + resolved "https://registry.yarnpkg.com/publint/-/publint-0.2.12.tgz#d25cd6bd243d5bdd640344ecdddb3eeafdcc4059" + integrity sha512-YNeUtCVeM4j9nDiTT2OPczmlyzOkIXNtdDZnSuajAxS/nZ6j3t7Vs9SUB4euQNddiltIwu7Tdd3s+hr08fAsMw== + dependencies: + npm-packlist "^5.1.3" + picocolors "^1.1.1" + sade "^1.8.1" + punycode@^2.1.0: version "2.3.0" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f" @@ -3023,20 +3015,6 @@ reusify@^1.0.4: resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== -rimraf@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" - integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== - dependencies: - glob "^7.1.3" - -run-applescript@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/run-applescript/-/run-applescript-5.0.0.tgz#e11e1c932e055d5c6b40d98374e0268d9b11899c" - integrity sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg== - dependencies: - execa "^5.0.0" - run-parallel@^1.1.9: version "1.2.0" resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" @@ -3044,6 +3022,13 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" +sade@^1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/sade/-/sade-1.8.1.tgz#0a78e81d658d394887be57d2a409bf703a3b2701" + integrity sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A== + dependencies: + mri "^1.1.0" + safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" @@ -3054,14 +3039,6 @@ safe-buffer@~5.2.0: resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -segfault-handler@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/segfault-handler/-/segfault-handler-1.3.0.tgz#054bc847832fa14f218ba6a79e42877501c8870e" - integrity sha512-p7kVHo+4uoYkr0jmIiTBthwV5L2qmWtben/KDunDZ834mbos+tY+iO0//HpAJpOFSQZZ+wxKWuRo4DxV02B7Lg== - dependencies: - bindings "^1.2.1" - nan "^2.14.0" - semver@^6.3.0, semver@^6.3.1: version "6.3.1" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" @@ -3079,6 +3056,11 @@ semver@^7.5.4: resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== +semver@^7.6.0: + version "7.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.1.tgz#abd5098d82b18c6c81f6074ff2647fd3e7220c9f" + integrity sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA== + shebang-command@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" @@ -3101,6 +3083,13 @@ sisteransi@^1.0.5: resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== +skin-tone@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/skin-tone/-/skin-tone-2.0.0.tgz#4e3933ab45c0d4f4f781745d64b9f4c208e41237" + integrity sha512-kUMbT1oBJCpgrnKoSr0o6wPtvRWT9W9UKvGLwfJYO2WuahZRHOpEyL1ckyMGgMWh0UdpmaoFqKKD29WTomNEGA== + dependencies: + unicode-emoji-modifier-base "^1.0.0" + slash@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" @@ -3184,20 +3173,15 @@ strip-final-newline@^2.0.0: resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== -strip-final-newline@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-3.0.0.tgz#52894c313fbff318835280aed60ff71ebf12b8fd" - integrity sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw== - strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== -superstruct@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/superstruct/-/superstruct-1.0.3.tgz#de626a5b49c6641ff4d37da3c7598e7a87697046" - integrity sha512-8iTn3oSS8nRGn+C2pgXSKPI3jmpm6FExNazNpjvqS6ZUJQCej3PUXEKM8NjHBOs54ExM+LPW/FBRhymrdcCiSg== +superstruct@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/superstruct/-/superstruct-1.0.4.tgz#0adb99a7578bd2f1c526220da6571b2d485d91ca" + integrity sha512-7JpaAoX2NGyoFlI9NBh66BQXGONc+uE+MRS5i2iOBKuS4e+ccgMDjATgZldkah+33DakBxDHiss9kvUcGAO8UQ== supports-color@^5.3.0: version "5.5.0" @@ -3206,7 +3190,7 @@ supports-color@^5.3.0: dependencies: has-flag "^3.0.0" -supports-color@^7.1.0: +supports-color@^7.0.0, supports-color@^7.1.0: version "7.2.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== @@ -3220,17 +3204,25 @@ supports-color@^8.0.0: dependencies: has-flag "^4.0.0" +supports-hyperlinks@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-3.1.0.tgz#b56150ff0173baacc15f21956450b61f2b18d3ac" + integrity sha512-2rn0BZ+/f7puLOHZm1HOJfwBggfaHXUpPUSSG/SWM4TWp5KCfmNYwnC3hruy2rZlMnmWZ+QAGpZfchu3f3695A== + dependencies: + has-flag "^4.0.0" + supports-color "^7.0.0" + supports-preserve-symlinks-flag@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== -synckit@^0.8.5: - version "0.8.6" - resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.8.6.tgz#b69b7fbce3917c2673cbdc0d87fb324db4a5b409" - integrity sha512-laHF2savN6sMeHCjLRkheIU4wo3Zg9Ln5YOjOo7sZ5dVQW8yF5pPE5SIw1dsPhq3TRp1jisKRCdPhfs/1WMqDA== +synckit@0.8.8, synckit@^0.9.1: + version "0.8.8" + resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.8.8.tgz#fe7fe446518e3d3d49f5e429f443cf08b6edfcd7" + integrity sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ== dependencies: - "@pkgr/utils" "^2.4.2" + "@pkgr/core" "^0.1.0" tslib "^2.6.2" test-exclude@^6.0.0: @@ -3242,15 +3234,19 @@ test-exclude@^6.0.0: glob "^7.1.4" minimatch "^3.0.4" -text-table@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" - integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== +thenify-all@^1.0.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" + integrity sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA== + dependencies: + thenify ">= 3.1.0 < 4" -titleize@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/titleize/-/titleize-3.0.0.tgz#71c12eb7fdd2558aa8a44b0be83b8a76694acd53" - integrity sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ== +"thenify@>= 3.1.0 < 4": + version "3.3.1" + resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.1.tgz#8932e686a4066038a016dd9e2ca46add9838a95f" + integrity sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw== + dependencies: + any-promise "^1.0.0" tmpl@1.0.5: version "1.0.5" @@ -3269,15 +3265,10 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" -tr46@~0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" - integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o= - -ts-api-utils@^1.0.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.3.0.tgz#4b490e27129f1e8e686b45cc4ab63714dc60eea1" - integrity sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ== +ts-api-utils@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-2.0.1.tgz#660729385b625b939aaa58054f45c058f33f10cd" + integrity sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w== ts-jest@^29.1.0: version "29.1.1" @@ -3312,21 +3303,20 @@ ts-node@^10.5.0: v8-compile-cache-lib "^3.0.0" yn "3.1.1" -tsc-multi@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/tsc-multi/-/tsc-multi-1.1.0.tgz#0e2b03c0ed0ac58ecb556f11709441102d202680" - integrity sha512-THE6X+sse7EZ2qMhqXvBhd2HMTvXyWwYnx+2T/ijqdp/6Rf7rUc2uPRzPdrrljZCNcYDeL0qP2P7tqm2IwayTg== +"tsc-multi@https://github.com/stainless-api/tsc-multi/releases/download/v1.1.3/tsc-multi.tgz": + version "1.1.3" + resolved "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.3/tsc-multi.tgz#8fc21fc95b247b86721b95fabfb10c6a436134c3" dependencies: - debug "^4.3.4" - fast-glob "^3.2.12" + debug "^4.3.7" + fast-glob "^3.3.2" get-stdin "^8.0.0" p-all "^3.0.0" - picocolors "^1.0.0" + picocolors "^1.1.1" signal-exit "^3.0.7" string-to-stream "^3.0.1" - superstruct "^1.0.3" - tslib "^2.5.0" - yargs "^17.7.1" + superstruct "^1.0.4" + tslib "^2.8.1" + yargs "^17.7.2" tsconfig-paths@^4.0.0: version "4.2.0" @@ -3337,16 +3327,16 @@ tsconfig-paths@^4.0.0: minimist "^1.2.6" strip-bom "^3.0.0" -tslib@^2.5.0: - version "2.6.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.0.tgz#b295854684dbda164e181d259a22cd779dcd7bc3" - integrity sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA== - -tslib@^2.6.0, tslib@^2.6.2: +tslib@^2.6.2: version "2.6.2" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== +tslib@^2.8.1: + version "2.8.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" + integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== + type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" @@ -3359,16 +3349,25 @@ type-detect@4.0.8: resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== -type-fest@^0.20.2: - version "0.20.2" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" - integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== - type-fest@^0.21.3: version "0.21.3" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== +typescript-eslint@^8.24.0: + version "8.24.0" + resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-8.24.0.tgz#cc655e71885ecb8280342b422ad839a2e2e46a96" + integrity sha512-/lmv4366en/qbB32Vz5+kCNZEMf6xYHwh1z48suBwZvAtnXKbP+YhGe8OLE2BqC67LMqKkCNLtjejdwsdW6uOQ== + dependencies: + "@typescript-eslint/eslint-plugin" "8.24.0" + "@typescript-eslint/parser" "8.24.0" + "@typescript-eslint/utils" "8.24.0" + +typescript@5.6.1-rc: + version "5.6.1-rc" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.6.1-rc.tgz#d5e4d7d8170174fed607b74cc32aba3d77018e02" + integrity sha512-E3b2+1zEFu84jB0YQi9BORDjz9+jGbwwy1Zi3G0LUNw7a7cePUrHMRNy8aPh53nXpkFGVHSxIZo5vKTfYaFiBQ== + typescript@^4.8.2: version "4.9.5" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" @@ -3379,10 +3378,15 @@ undici-types@~5.26.4: resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== -untildify@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/untildify/-/untildify-4.0.0.tgz#2bc947b953652487e4600949fb091e3ae8cd919b" - integrity sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw== +undici-types@~6.19.2: + version "6.19.8" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" + integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== + +unicode-emoji-modifier-base@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unicode-emoji-modifier-base/-/unicode-emoji-modifier-base-1.0.0.tgz#dbbd5b54ba30f287e2a8d5a249da6c0cef369459" + integrity sha512-yLSH4py7oFH3oG/9K+XWrz1pSi3dfUrWEnInbxMfArOfc1+33BlGPQtLsOYwvdMy11AwUBetYuaRxSPqgkq+8g== update-browserslist-db@^1.0.13: version "1.0.13" @@ -3418,6 +3422,11 @@ v8-to-istanbul@^9.0.1: "@types/istanbul-lib-coverage" "^2.0.1" convert-source-map "^2.0.0" +validate-npm-package-name@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/validate-npm-package-name/-/validate-npm-package-name-5.0.1.tgz#a316573e9b49f3ccd90dbb6eb52b3f06c6d604e8" + integrity sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ== + walker@^1.0.8: version "1.0.8" resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" @@ -3425,24 +3434,6 @@ walker@^1.0.8: dependencies: makeerror "1.0.12" -web-streams-polyfill@4.0.0-beta.1: - version "4.0.0-beta.1" - resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.1.tgz#3b19b9817374b7cee06d374ba7eeb3aeb80e8c95" - integrity sha512-3ux37gEX670UUphBF9AMCq8XM6iQ8Ac6A+DSRRjDoRBm1ufCkaCDdNVbaqq60PsEkdNlLKrGtv/YBP4EJXqNtQ== - -webidl-conversions@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" - integrity sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE= - -whatwg-url@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" - integrity sha1-lmRU6HZUYuN2RNNib2dCzotwll0= - dependencies: - tr46 "~0.0.3" - webidl-conversions "^3.0.0" - which@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" @@ -3472,6 +3463,11 @@ write-file-atomic@^4.0.2: imurmurhash "^0.1.4" signal-exit "^3.0.7" +ws@^8.18.0: + version "8.18.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.0.tgz#0d7505a6eafe2b0e712d232b42279f53bc289bbc" + integrity sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw== + y18n@^5.0.5: version "5.0.8" resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" @@ -3487,12 +3483,30 @@ yallist@^4.0.0: resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== +yargs-parser@^20.2.2: + version "20.2.9" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" + integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== + yargs-parser@^21.0.1, yargs-parser@^21.1.1: version "21.1.1" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== -yargs@^17.3.1, yargs@^17.7.1: +yargs@^16.0.0: + version "16.2.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" + integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.0" + y18n "^5.0.5" + yargs-parser "^20.2.2" + +yargs@^17.3.1, yargs@^17.7.2: version "17.7.2" resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== @@ -3516,6 +3530,6 @@ yocto-queue@^0.1.0: integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== zod@^3.23.8: - version "3.23.8" - resolved "https://registry.yarnpkg.com/zod/-/zod-3.23.8.tgz#e37b957b5d52079769fb8097099b592f0ef4067d" - integrity sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g== + version "3.24.1" + resolved "https://registry.yarnpkg.com/zod/-/zod-3.24.1.tgz#27445c912738c8ad1e9de1bea0359fa44d9d35ee" + integrity sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==