diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 763462fad..43fd5a73f 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -9,9 +9,7 @@ "postCreateCommand": "yarn install", "customizations": { "vscode": { - "extensions": [ - "esbenp.prettier-vscode" - ] + "extensions": ["esbenp.prettier-vscode"] } } } 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 09f1636b6..99a5453f2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -12,14 +12,14 @@ jobs: lint: timeout-minutes: 10 name: lint - runs-on: ${{ github.repository == 'stainless-sdks/openai-node' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} + runs-on: ${{ github.repository == 'stainless-sdks/openai-typescript' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} steps: - uses: actions/checkout@v4 - name: Set up Node uses: actions/setup-node@v4 with: - node-version: '18' + node-version: '20' - name: Bootstrap run: ./scripts/bootstrap @@ -30,7 +30,7 @@ jobs: build: timeout-minutes: 5 name: build - runs-on: ${{ github.repository == 'stainless-sdks/openai-node' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} + runs-on: ${{ github.repository == 'stainless-sdks/openai-typescript' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} permissions: contents: read id-token: write @@ -40,7 +40,7 @@ jobs: - name: Set up Node uses: actions/setup-node@v4 with: - node-version: '18' + node-version: '20' - name: Bootstrap run: ./scripts/bootstrap @@ -49,14 +49,14 @@ jobs: run: ./scripts/build - name: Get GitHub OIDC Token - if: github.repository == 'stainless-sdks/openai-node' + if: github.repository == 'stainless-sdks/openai-typescript' id: github-oidc uses: actions/github-script@v6 with: script: core.setOutput('github_token', await core.getIDToken()); - name: Upload tarball - if: github.repository == 'stainless-sdks/openai-node' + if: github.repository == 'stainless-sdks/openai-typescript' env: URL: https://pkg.stainless.com/s AUTH: ${{ steps.github-oidc.outputs.github_token }} @@ -65,7 +65,7 @@ jobs: test: timeout-minutes: 10 name: test - runs-on: ${{ github.repository == 'stainless-sdks/openai-node' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} + runs-on: ${{ github.repository == 'stainless-sdks/openai-typescript' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} steps: - uses: actions/checkout@v4 @@ -83,7 +83,7 @@ jobs: examples: timeout-minutes: 10 name: examples - runs-on: ${{ github.repository == 'stainless-sdks/openai-node' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} + runs-on: ${{ github.repository == 'stainless-sdks/openai-typescript' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} if: github.repository == 'openai/openai-node' steps: @@ -97,10 +97,10 @@ jobs: run: | yarn install - - env: + - env: OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} run: | - yarn tsn examples/demo.ts + yarn tsn examples/demo.ts ecosystem_tests: name: ecosystem tests (v${{ matrix.node-version }}) diff --git a/.github/workflows/create-releases.yml b/.github/workflows/create-releases.yml index 19b7dd831..e3eaa86dd 100644 --- a/.github/workflows/create-releases.yml +++ b/.github/workflows/create-releases.yml @@ -47,4 +47,3 @@ jobs: if: ${{ steps.release.outputs.releases_created }} run: | bash ./bin/publish-jsr - diff --git a/.github/workflows/release-doctor.yml b/.github/workflows/release-doctor.yml index 37bc09e80..3bb1d714f 100644 --- a/.github/workflows/release-doctor.yml +++ b/.github/workflows/release-doctor.yml @@ -21,4 +21,3 @@ jobs: env: STAINLESS_API_KEY: ${{ secrets.STAINLESS_API_KEY }} NPM_TOKEN: ${{ secrets.OPENAI_NPM_TOKEN || secrets.NPM_TOKEN }} - diff --git a/.release-please-manifest.json b/.release-please-manifest.json index e7bff8e4e..32dbe0e2b 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "4.104.0" + ".": "5.0.0" } diff --git a/CHANGELOG.md b/CHANGELOG.md index 22fe5f789..d4696422c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,271 @@ # Changelog +## 5.0.0 (2025-05-29) + +Full Changelog: [v5.0.0-alpha.0...v5.0.0](https://github.com/openai/openai-node/compare/v5.0.0-alpha.0...v5.0.0) + +### Features + +* add audio helpers ([ec5067d](https://github.com/openai/openai-node/commit/ec5067deba1fe4202d90db42e45c3bd774936af1)) +* add migration guide ([cfd2088](https://github.com/openai/openai-node/commit/cfd2088219464381077dec62d38d1830ab0b43f3)) +* add SKIP_BREW env var to ./scripts/bootstrap ([7ea4a24](https://github.com/openai/openai-node/commit/7ea4a244d5b39e0745aea1a89abff940e2c3922f)) +* **api:** add /v1/responses and built-in tools ([91af47c](https://github.com/openai/openai-node/commit/91af47cc4f62b08a451bc39f44c64244a71c1f2c)) +* **api:** add /v1/responses and built-in tools ([0612242](https://github.com/openai/openai-node/commit/06122424a4d783aff07b7089b64986fb35bc24e4)) +* **api:** add `get /chat/completions` endpoint ([9697139](https://github.com/openai/openai-node/commit/9697139a5f38bcc2dffa3322ff575eb1fc8b4e35)) +* **api:** add `get /chat/completions` endpoint ([16c67be](https://github.com/openai/openai-node/commit/16c67be29bbb976660ac01d76f54e8735e71c1e0)) +* **api:** add `get /responses/{response_id}/input_items` endpoint ([f2c5aba](https://github.com/openai/openai-node/commit/f2c5aba736f99550a9a7837be22b39b36a7495d0)) +* **api:** add `get /responses/{response_id}/input_items` endpoint ([3676d34](https://github.com/openai/openai-node/commit/3676d34127cd88a67dde6e6d24f2b6a7b65d3073)) +* **api:** add container endpoint ([3ffca5c](https://github.com/openai/openai-node/commit/3ffca5c5b2dc6819e955ed343b2bb6e2095e7bdf)) +* **api:** add container endpoint ([e973476](https://github.com/openai/openai-node/commit/e9734764625275c50ef612ff934804be8cb2adff)) +* **api:** Add evalapi to sdk ([70092d7](https://github.com/openai/openai-node/commit/70092d768426b8e0dd4bca21e7a3dea009e25b9f)) +* **api:** Add evalapi to sdk ([#1456](https://github.com/openai/openai-node/issues/1456)) ([33b66f5](https://github.com/openai/openai-node/commit/33b66f517e756e63c676efee97f7122b3cf165d1)) +* **api:** add gpt-4.5-preview ([1d4478d](https://github.com/openai/openai-node/commit/1d4478d7935028e20a9d9d11ff29ff8b991c44f9)) +* **api:** add gpt-4.5-preview ([#1349](https://github.com/openai/openai-node/issues/1349)) ([bb269a1](https://github.com/openai/openai-node/commit/bb269a1a6fda11c533fb88fa1250a342a5a11ed0)) +* **api:** add image sizes, reasoning encryption ([0c25021](https://github.com/openai/openai-node/commit/0c2502187f8895f029277a7be9825862f458e9aa)) +* **api:** add image sizes, reasoning encryption ([31cd88f](https://github.com/openai/openai-node/commit/31cd88fae84f630c8e86e1acab6c4cd9283c886c)) +* **api:** add o3 and o4-mini model IDs ([19cda5d](https://github.com/openai/openai-node/commit/19cda5d3b908238ae6c6f5609ac3a118d4d8acc2)) +* **api:** add o3 and o4-mini model IDs ([a0d0000](https://github.com/openai/openai-node/commit/a0d000094f69db82974de4ba792cd07d4ab59c21)) +* **api:** Add reinforcement fine-tuning api support ([e6bbaf5](https://github.com/openai/openai-node/commit/e6bbaf577aa6bdf3bcdaf25a5a7d4e8202831c7a)) +* **api:** Add reinforcement fine-tuning api support ([fabe6ec](https://github.com/openai/openai-node/commit/fabe6ec948c08c11588f6168f0a7560bf307d780)) +* **api:** add support for storing chat completions ([59da177](https://github.com/openai/openai-node/commit/59da1771b93158d5d89efc9e63e1ef9c09a634f3)) +* **api:** add support for storing chat completions ([#1327](https://github.com/openai/openai-node/issues/1327)) ([be1ca6b](https://github.com/openai/openai-node/commit/be1ca6b9a6732214ac21ca375b5b0a9b7f492fd6)) +* **api:** adding gpt-4.1 family of model IDs ([8a2a745](https://github.com/openai/openai-node/commit/8a2a7454bee0fbe9e4729d47f6b894e5f25d68f5)) +* **api:** adding gpt-4.1 family of model IDs ([840e7de](https://github.com/openai/openai-node/commit/840e7de7870835488d4c823d97afdf5d53a739be)) +* **api:** adding new image model support ([a0010fd](https://github.com/openai/openai-node/commit/a0010fdb60fe723ebc70103cceca552aca51855e)) +* **api:** adding new image model support ([c353531](https://github.com/openai/openai-node/commit/c353531a238863e7f386a66dcee9f02b8115dd47)) +* **api:** Config update for pakrym-stream-param ([71c3d31](https://github.com/openai/openai-node/commit/71c3d31dad568030fd563a0b5c7c2bd26d472df1)) +* **api:** Config update for pakrym-stream-param ([b4d1b46](https://github.com/openai/openai-node/commit/b4d1b4627622157593a06f64f02ee5aa72deb6b3)) +* **api:** Config update for pakrym-stream-param ([469ad7b](https://github.com/openai/openai-node/commit/469ad7b9d76b674aa3fd829128a54758ab7adfbd)) +* **api:** further updates for evals API ([3019a7e](https://github.com/openai/openai-node/commit/3019a7e67614942b5dc6d7e788f2b5b30b3bc874)) +* **api:** further updates for evals API ([3f6f248](https://github.com/openai/openai-node/commit/3f6f248191b45015924be76fd5154d149c4ed8a0)) +* **api:** manual updates ([debe529](https://github.com/openai/openai-node/commit/debe5295d077f79cc4b4eefefb008e5a10b32793)) +* **api:** manual updates ([e83286b](https://github.com/openai/openai-node/commit/e83286b10b20d3e4c02903739b045af5cbf71cde)) +* **api:** manual updates ([959eace](https://github.com/openai/openai-node/commit/959eace6ec132a83f731fa496d5b8b7a11fa6bb2)) +* **api:** manual updates ([179a607](https://github.com/openai/openai-node/commit/179a607a89fabda32ebad62cc7ee86b5332a29f4)) +* **api:** manual updates ([0cb0c86](https://github.com/openai/openai-node/commit/0cb0c863b3bda6e6d72b3b5cdba3c8791db9bb77)) +* **api:** manual updates ([678ae6b](https://github.com/openai/openai-node/commit/678ae6b7112ed9b27d092b3234dd034d572deb9c)) +* **api:** manual updates ([4560dc6](https://github.com/openai/openai-node/commit/4560dc62f8c65e9857085409e382760aa601d60b)) +* **api:** manual updates ([554c3b1](https://github.com/openai/openai-node/commit/554c3b142024bec8010474cd7e42b99a209d4daa)) +* **api:** manual updates ([b893d81](https://github.com/openai/openai-node/commit/b893d81420359c712dab6997c2dbc9f309549712)) +* **api:** manual updates ([c1c2819](https://github.com/openai/openai-node/commit/c1c281983e23dcfdca964720265d3cba28b17795)) +* **api:** manual updates ([efce6d3](https://github.com/openai/openai-node/commit/efce6d3d719ad463b035b22e9a1cf461ab62b5af)) +* **api:** manual updates ([32afb00](https://github.com/openai/openai-node/commit/32afb0022939b19069c37fcd9cabfe666ea86b77)) +* **api:** new API tools ([0cc8994](https://github.com/openai/openai-node/commit/0cc899456091f0b13fc98daa03a4299473f528dc)) +* **api:** new API tools ([fb4014f](https://github.com/openai/openai-node/commit/fb4014ffac7b220d37bd03c94fa745386b010bf0)) +* **api:** new models for TTS, STT, + new audio features for Realtime ([1eab9ed](https://github.com/openai/openai-node/commit/1eab9edf9e5eb08e7c3d0d0ff21f378cacf7cb5b)) +* **api:** new models for TTS, STT, + new audio features for Realtime ([#1407](https://github.com/openai/openai-node/issues/1407)) ([d11b13c](https://github.com/openai/openai-node/commit/d11b13cdf5412f03e551365297a27e610a36edda)) +* **api:** new streaming helpers for background responses ([c071491](https://github.com/openai/openai-node/commit/c07149125128687f026df0d04b304167cf6c9910)) +* **api:** new streaming helpers for background responses ([1ddd6ff](https://github.com/openai/openai-node/commit/1ddd6ff182b09d696954fda4bde50fb82f1d6585)) +* **api:** o1-pro now available through the API ([3540b06](https://github.com/openai/openai-node/commit/3540b069fcec32ab5acbdf3def579f21759dada6)) +* **api:** o1-pro now available through the API ([#1398](https://github.com/openai/openai-node/issues/1398)) ([aefd267](https://github.com/openai/openai-node/commit/aefd2675154ff848032a7fec856f0db6ed2ad629)) +* **api:** responses x eval api ([b349ade](https://github.com/openai/openai-node/commit/b349adeff0df0b6c56d937da082900e7331d1ab6)) +* **api:** responses x eval api ([ea1d56c](https://github.com/openai/openai-node/commit/ea1d56c979ad7136aa584a773904b0570ba14783)) +* **api:** Updating Assistants and Evals API schemas ([e68f598](https://github.com/openai/openai-node/commit/e68f598107aba01ce1bcab61ac616d4cf70380c9)) +* **api:** Updating Assistants and Evals API schemas ([8cc63d3](https://github.com/openai/openai-node/commit/8cc63d351057678d474fe1a16e3077370c83fddb)) +* **client:** accept RFC6838 JSON content types ([67da9ce](https://github.com/openai/openai-node/commit/67da9ce89ea010813779b98c18fea84d9964c7de)) +* **client:** add Realtime API support ([7737d25](https://github.com/openai/openai-node/commit/7737d2547c5c6c45004fe281b8122c9e2adc0efb)) +* **client:** add withOptions helper ([7e9ea85](https://github.com/openai/openai-node/commit/7e9ea85f63a0989b3446834d9e1a94c0d050cf87)) +* **client:** improve logging ([ead0ba4](https://github.com/openai/openai-node/commit/ead0ba4dc9f51c35007c5fe20f9954855f558652)) +* **client:** promote beta completions methods to GA ([4c622f9](https://github.com/openai/openai-node/commit/4c622f9f55529e3aab30c834349d341038499db1)) +* version 5 ([855144b](https://github.com/openai/openai-node/commit/855144b105c647b91a389c08c07f215d39ff8920)) +* version 5 ([855144b](https://github.com/openai/openai-node/commit/855144b105c647b91a389c08c07f215d39ff8920)) + + +### Bug Fixes + +* **api:** add missing file rank enum + more metadata ([b943a0a](https://github.com/openai/openai-node/commit/b943a0ae4682a410172e1063a9424f5150cd9010)) +* **api:** correct some Responses types ([3ca8965](https://github.com/openai/openai-node/commit/3ca89652489e911890d0be9a2e93341ef026a20f)) +* **api:** correct some Responses types ([#1391](https://github.com/openai/openai-node/issues/1391)) ([e983d0c](https://github.com/openai/openai-node/commit/e983d0c61d33b106f149d87eed90378bd0bbc349)) +* **api:** improve type resolution when importing as a package ([b6bf469](https://github.com/openai/openai-node/commit/b6bf4694cbd0ab86e7d6689289faed9ddbfb46ee)) +* **api:** improve type resolution when importing as a package ([#1444](https://github.com/openai/openai-node/issues/1444)) ([4af79dd](https://github.com/openai/openai-node/commit/4af79ddd5b19925fa09d9ae877470aa8304535c2)) +* **assistants:** handle `thread.run.incomplete` event ([a2714bb](https://github.com/openai/openai-node/commit/a2714bb5253ade80cb15455ceb8f6dbea63cb1d0)) +* **audio:** correctly handle transcription streaming ([9c7d352](https://github.com/openai/openai-node/commit/9c7d352181c690156e26c9538c00edff6db5b384)) +* avoid type error in certain environments ([#1413](https://github.com/openai/openai-node/issues/1413)) ([f395e95](https://github.com/openai/openai-node/commit/f395e9584ac63780442bb54c2d292914eaecf3c7)) +* **azure/audio:** use model param for deployments ([0eda70a](https://github.com/openai/openai-node/commit/0eda70adc3c88c12792c1eee9c3279579a86d412)) +* **azure:** add /images/edits to deployments endpoints ([#1509](https://github.com/openai/openai-node/issues/1509)) ([4b18059](https://github.com/openai/openai-node/commit/4b180597633a527c435e049d885103ab06311b90)) +* **azure:** add /images/edits to deployments endpoints ([#1509](https://github.com/openai/openai-node/issues/1509)) ([84fc31a](https://github.com/openai/openai-node/commit/84fc31aa903eceeb80815f6b17562fc463a71cfc)) +* **azure:** use correct internal method ([a9c7821](https://github.com/openai/openai-node/commit/a9c78216d88379bc1d5103b30970f041d22083b8)) +* **client:** always overwrite when merging headers ([c160550](https://github.com/openai/openai-node/commit/c160550761eed22b038ac8a5b477729fe298834c)) +* **client:** fix export map for index exports ([#1328](https://github.com/openai/openai-node/issues/1328)) ([26d5868](https://github.com/openai/openai-node/commit/26d5868dd53045bc820a607100eab1070785f50c)) +* **client:** fix export map for index exports, accept BunFile ([9416c96](https://github.com/openai/openai-node/commit/9416c96fdc12c9ea22da04ac317d93cb2ad94f57)) +* **client:** fix TypeError with undefined File ([0e980d0](https://github.com/openai/openai-node/commit/0e980d05e8e1fb4befae443fb84b8b9fab8dbd50)) +* **client:** remove duplicate types ([bee2ce5](https://github.com/openai/openai-node/commit/bee2ce5841f25b1f56cdc1fd0b36b0758d2c9bdc)) +* **client:** remove duplicate types ([#1410](https://github.com/openai/openai-node/issues/1410)) ([23fd3ff](https://github.com/openai/openai-node/commit/23fd3ffef3b19656b27576b4d0c613d19ea1ae2f)) +* **client:** return binary content from `get /containers/{container_id}/files/{file_id}/content` ([8502966](https://github.com/openai/openai-node/commit/8502966ed2fee9162ad14fdf04c893e1fa130a51)) +* **client:** return binary content from `get /containers/{container_id}/files/{file_id}/content` ([899869b](https://github.com/openai/openai-node/commit/899869b40ab5f64145c48521378f1925f6b5b33a)) +* **client:** return binary content from `get /containers/{container_id}/files/{file_id}/content` ([83129d7](https://github.com/openai/openai-node/commit/83129d7eac3dd784bb1c29fa344c5b808a59db73)) +* **client:** send `X-Stainless-Timeout` in seconds ([5a272a7](https://github.com/openai/openai-node/commit/5a272a76515b09810fcb5d0ca63dd6050d1a8023)) +* **client:** send `X-Stainless-Timeout` in seconds ([#1442](https://github.com/openai/openai-node/issues/1442)) ([5e5e460](https://github.com/openai/openai-node/commit/5e5e4607a103fcb6257c071bb4bf57902ee6415f)) +* **client:** send all configured auth headers ([ee01414](https://github.com/openai/openai-node/commit/ee01414c206f18a537f3616bcf1e208aab311030)) +* compat with more runtimes ([f743730](https://github.com/openai/openai-node/commit/f74373020ab01ace999a72d916e017db0177bf16)) +* correct imports ([21f2107](https://github.com/openai/openai-node/commit/21f210782b1ee3b33231cfed0277ab8e3a764bcb)) +* correctly decode multi-byte characters over multiple chunks ([f3d7083](https://github.com/openai/openai-node/commit/f3d708390a36427206edfc67875a7987eb483e55)) +* **docs:** correct docstring on responses.stream ([1847673](https://github.com/openai/openai-node/commit/1847673de09586c809e1057a6b08c604471e13ff)) +* **ecosystem-tests/bun:** bump dependencies ([1e52734](https://github.com/openai/openai-node/commit/1e52734e28a0e474b11c90977fd3161ea2e50f8c)) +* **ecosystem-tests/cloudflare-worker:** ignore lib errors for now ([157248a](https://github.com/openai/openai-node/commit/157248ae85d2261f9538128703d0ebbc24347c61)) +* **ecosystem-tests:** correct ecosystem tests setup ([6fa0675](https://github.com/openai/openai-node/commit/6fa06756624071fb1486c69a496ba906fef96de2)) +* **embeddings:** correctly decode base64 data ([#1448](https://github.com/openai/openai-node/issues/1448)) ([d6b99c8](https://github.com/openai/openai-node/commit/d6b99c8fcbd35ef6b45d66f487aea759c01febbc)) +* **exports:** add missing type exports ([a816029](https://github.com/openai/openai-node/commit/a81602996a1d9c3ceda79d88fe163a1e6b823e77)) +* **exports:** add missing type exports ([#1417](https://github.com/openai/openai-node/issues/1417)) ([06c03d7](https://github.com/openai/openai-node/commit/06c03d7125d8331679dd206d0e34705d65669046)) +* **exports:** ensure resource imports don't require /index ([d028ad7](https://github.com/openai/openai-node/commit/d028ad7b0debb585534acb73fa5cafe6f8d90f37)) +* **helpers/zod:** error on optional + not nullable fields ([6e424b5](https://github.com/openai/openai-node/commit/6e424b5cac1b2ea7e108ce24154be5bdddf56bdd)) +* **internal:** add mts file + crypto shim types ([a06deb8](https://github.com/openai/openai-node/commit/a06deb8aec21ecf8bfbc369112da10a790039178)) +* **internal:** clean up undefined File test ([da43aa9](https://github.com/openai/openai-node/commit/da43aa91586fe80137c6500e850dca82085936b8)) +* **internal:** fix file uploads in node 18 jest ([abfff03](https://github.com/openai/openai-node/commit/abfff03f49e62e195d112229127be674cc44497d)) +* **internal:** work around https://github.com/vercel/next.js/issues/76881 ([#1427](https://github.com/openai/openai-node/issues/1427)) ([84edc62](https://github.com/openai/openai-node/commit/84edc62d05eddaefee0973f9687fcfdd43b0afa9)) +* **jsr:** correct zod config ([04e30c0](https://github.com/openai/openai-node/commit/04e30c03ce0496a718aebf4cc2daac82ebba1ddb)) +* **jsr:** export realtime helpers ([0ea64eb](https://github.com/openai/openai-node/commit/0ea64eb2bde99e243761ea2e3d9d3c294c9f7fbc)) +* **jsr:** export zod helpers ([77e1180](https://github.com/openai/openai-node/commit/77e118082334710cab361efb95934422e4db6b18)) +* **mcp:** remove unused tools.ts ([752f4f1](https://github.com/openai/openai-node/commit/752f4f182116df46e4e25d6f94dcffbe504b89fd)) +* **mcp:** remove unused tools.ts ([#1445](https://github.com/openai/openai-node/issues/1445)) ([4ba9947](https://github.com/openai/openai-node/commit/4ba994773b41a3ed05a3ad908b235fc5f3810dfc)) +* optimize sse chunk reading off-by-one error ([a7effe8](https://github.com/openai/openai-node/commit/a7effe8ba3a65a535ae082d3d4e0d639aba7b7c1)) +* optimize sse chunk reading off-by-one error ([#1339](https://github.com/openai/openai-node/issues/1339)) ([b0b4189](https://github.com/openai/openai-node/commit/b0b4189420e1c5bb5fc4bbb8925f88fe65f9b217)) +* **package:** add chat/completions.ts back in ([#1333](https://github.com/openai/openai-node/issues/1333)) ([ee34833](https://github.com/openai/openai-node/commit/ee34833b6d097bda278ea07d261527e0bf51bf65)) +* **package:** add chat/completions.ts back in ([#1333](https://github.com/openai/openai-node/issues/1333)) ([1f38cc1](https://github.com/openai/openai-node/commit/1f38cc1976f4091a90a38d49e6ddc1c22e5c39ab)) +* **parsing:** remove tool_calls default empty array ([#1341](https://github.com/openai/openai-node/issues/1341)) ([40e8dd2](https://github.com/openai/openai-node/commit/40e8dd2de0329c6cff53717d49c6e07852b352e2)) +* **parsing:** remove tool_calls default empty array ([#1341](https://github.com/openai/openai-node/issues/1341)) ([6d056bf](https://github.com/openai/openai-node/commit/6d056bf95c9be4046decf20ec4c98dfa2bea2723)) +* **realtime:** call .toString() on WebSocket url ([#1324](https://github.com/openai/openai-node/issues/1324)) ([6e9444c](https://github.com/openai/openai-node/commit/6e9444c6c77a93ff4ce06bd5b27a9c236ba6f307)) +* **responses:** correct computer use enum value ([66fb815](https://github.com/openai/openai-node/commit/66fb8157217de604d7f535e917b085fa8b6754d4)) +* **responses:** correct reasoning output type ([1698b95](https://github.com/openai/openai-node/commit/1698b95af215ed5a3f0fcf512779efe89a95d4d2)) +* **responses:** correct reasoning output type ([9cb9576](https://github.com/openai/openai-node/commit/9cb95763cab5678c5098b37ad0fe1ec83d2c1cb7)) +* **responses:** correctly add output_text ([8ae07cc](https://github.com/openai/openai-node/commit/8ae07cc036895529a028134451fe2ab5c1661871)) +* **responses:** support streaming retrieve calls ([657807c](https://github.com/openai/openai-node/commit/657807c2d7cbf2c6fc9a92ce98bb7295bb156326)) +* **tests/embeddings:** avoid cross-realm issue ([aceaac0](https://github.com/openai/openai-node/commit/aceaac05c05fa318c4bff7ff340b512a6bd904b9)) +* **tests:** don't rely on OPENAI_API_KEY env variable ([087580a](https://github.com/openai/openai-node/commit/087580ae5ebedc88f6f219c7d00c08607722a519)) +* **tests:** manually reset node:buffer File ([1d18ed4](https://github.com/openai/openai-node/commit/1d18ed4f90436e7041835d201c8cb1c373ded418)) +* **tests:** port tests to new setup ([9eb9854](https://github.com/openai/openai-node/commit/9eb98543660c86f0b11766ef95b35fa28fd16e47)) +* **tests:** stop using node:stream ([317a04d](https://github.com/openai/openai-node/commit/317a04d8d189ee33a9dd5308668296a708b391a8)) +* **threads:** remove unused duplicative types ([0b77c7c](https://github.com/openai/openai-node/commit/0b77c7c9da64962fd50854be06661cdce549d326)) +* **types:** export AssistantStream ([#1472](https://github.com/openai/openai-node/issues/1472)) ([bc492ba](https://github.com/openai/openai-node/commit/bc492ba124cddd545eec7a1199712452c573a7a4)) +* **types:** export ParseableToolsParams ([#1486](https://github.com/openai/openai-node/issues/1486)) ([3e7c92c](https://github.com/openai/openai-node/commit/3e7c92c8a76c1f747610d63d9d69a88b796ee9fc)) +* **types:** ignore missing `id` in responses pagination ([d2be74a](https://github.com/openai/openai-node/commit/d2be74a28dec48cd7d88db88af95e8bc608cdede)) +* **types:** improve responses type names ([96ed4db](https://github.com/openai/openai-node/commit/96ed4dbd0c142d30d6cf80c2f850e77e02bd47a4)) +* **types:** improve responses type names ([#1392](https://github.com/openai/openai-node/issues/1392)) ([4548326](https://github.com/openai/openai-node/commit/454832606ebe9d5cf8ffd436eac09375f682c495)) +* **zod:** warn on optional field usage ([#1469](https://github.com/openai/openai-node/issues/1469)) ([aea2d12](https://github.com/openai/openai-node/commit/aea2d123d200e6a7eae11e66583127270a8db8bf)) + + +### Performance Improvements + +* **embedding:** default embedding creation to base64 ([#1312](https://github.com/openai/openai-node/issues/1312)) ([be00d29](https://github.com/openai/openai-node/commit/be00d29fadb2b78920bcae1e6e72750bc6f973a4)), closes [#1310](https://github.com/openai/openai-node/issues/1310) + + +### Chores + +* add hash of OpenAPI spec/config inputs to .stats.yml ([1b0a94d](https://github.com/openai/openai-node/commit/1b0a94d088c2891fcad0ca0de3a1e4e205a7c9cf)) +* add hash of OpenAPI spec/config inputs to .stats.yml ([48921aa](https://github.com/openai/openai-node/commit/48921aaabc3456408907e4bcf1cc074a9228c459)) +* add missing type alias exports ([5d75cb9](https://github.com/openai/openai-node/commit/5d75cb95019ae77eafb0c878b355f09a1f87c3bd)) +* add missing type alias exports ([#1390](https://github.com/openai/openai-node/issues/1390)) ([f4647cc](https://github.com/openai/openai-node/commit/f4647cc7546d06145bf34113be22aabbd1b7e7ee)) +* **api:** updates to supported Voice IDs ([28130c7](https://github.com/openai/openai-node/commit/28130c7fe172dd90fcf2036dc72750e485e42645)) +* **api:** updates to supported Voice IDs ([#1424](https://github.com/openai/openai-node/issues/1424)) ([fb0e96a](https://github.com/openai/openai-node/commit/fb0e96a7fa8c020ac6109951bb36f9a4ada24d03)) +* **ci:** add timeout thresholds for CI jobs ([5775451](https://github.com/openai/openai-node/commit/5775451a55212687ba998b332c1394528d98121f)) +* **ci:** add timeout thresholds for CI jobs ([939f636](https://github.com/openai/openai-node/commit/939f6365c304c037e0473207d85bbc2f2731b105)) +* **ci:** bump node version for release workflows ([bbf5d45](https://github.com/openai/openai-node/commit/bbf5d45259a8bfba62e2217955597ec0f6cfead4)) +* **ci:** only use depot for staging repos ([c59c3b5](https://github.com/openai/openai-node/commit/c59c3b5ead95b424b27c8c9f2120ad4283fb280e)) +* **ci:** only use depot for staging repos ([214da39](https://github.com/openai/openai-node/commit/214da398c76f46d40994665f3ca7e10e203e9579)) +* **ci:** run on more branches and use depot runners ([e17a4f8](https://github.com/openai/openai-node/commit/e17a4f8e1fc3de02c953421debf39827ea72d52c)) +* **ci:** run on more branches and use depot runners ([ead76fc](https://github.com/openai/openai-node/commit/ead76fc6429ac52a1c8b008ac5c0afcefaa0bae5)) +* **client:** drop support for EOL node versions ([a326944](https://github.com/openai/openai-node/commit/a326944e8a8822bc70f86d7046de3142f9dff530)) +* **client:** expose headers on some streaming errors ([#1423](https://github.com/openai/openai-node/issues/1423)) ([6c93a23](https://github.com/openai/openai-node/commit/6c93a23b79f335a21c65b52d1192890a5325ed6d)) +* **client:** minor internal fixes ([5032c28](https://github.com/openai/openai-node/commit/5032c2802bd51885270badf47e27768f62240d25)) +* **client:** minor internal fixes ([6558b7c](https://github.com/openai/openai-node/commit/6558b7ca8aef2f98f47a07bc206eb4a789097510)) +* **client:** more accurate streaming errors ([0c21914](https://github.com/openai/openai-node/commit/0c21914d90b0ef1073d99c539cf9ef18912b8d0b)) +* **client:** move misc public files to new `core/` directory, deprecate old paths ([38c9d54](https://github.com/openai/openai-node/commit/38c9d548fded9000cde85270b38085c61905b5c1)) +* **client:** only accept standard types for file uploads ([53e35c8](https://github.com/openai/openai-node/commit/53e35c8b10a8e3ef95c0d644d59ab915225b8114)) +* deprecate Assistants API ([0be23b9](https://github.com/openai/openai-node/commit/0be23b98b6be9f8922d035270b1c907307010a29)) +* deprecate Assistants API ([1726e6b](https://github.com/openai/openai-node/commit/1726e6bfe0f4e83db79ac2f2939b4131d797b42a)) +* deprecate Assistants API ([5b34fcd](https://github.com/openai/openai-node/commit/5b34fcdd1454b8cccbaaf05ace6516afb3b09273)) +* **docs:** add missing deprecation warnings ([5495529](https://github.com/openai/openai-node/commit/54955295ff5c7ab0fecb522b3aaadaaecb229d51)) +* **docs:** add missing deprecation warnings ([995075b](https://github.com/openai/openai-node/commit/995075b632051b5bb33c0381056107b2fe93931e)) +* **docs:** grammar improvements ([d5d62b0](https://github.com/openai/openai-node/commit/d5d62b0c45273e746e25e389c0e268f3f463eec1)) +* **docs:** grammar improvements ([7761cfb](https://github.com/openai/openai-node/commit/7761cfb0a8a56d056a73c046a6a613f66ada4abe)) +* **docs:** improve docs for withResponse/asResponse ([9f4c30b](https://github.com/openai/openai-node/commit/9f4c30b9bcc2f373b3087dba69bd837f96f79d81)) +* **docs:** improve migration doc ([732d870](https://github.com/openai/openai-node/commit/732d87001cbd9aa095e7b58dc843e86547e3f510)) +* **docs:** update zod tool call example, fix azure tests ([f18ced8](https://github.com/openai/openai-node/commit/f18ced883e4b5d689e0569d9b163b1958688b669)) +* **exports:** cleaner resource index imports ([0da1c16](https://github.com/openai/openai-node/commit/0da1c1653896f872b9f17e8a3248c8206994c535)) +* **exports:** cleaner resource index imports ([#1396](https://github.com/openai/openai-node/issues/1396)) ([023d106](https://github.com/openai/openai-node/commit/023d106185abf62f892bff66faf617eb45777004)) +* **exports:** stop using path fallbacks ([09af7ff](https://github.com/openai/openai-node/commit/09af7ffd42458c6c26d9325060fcb8925aca7c81)) +* **exports:** stop using path fallbacks ([#1397](https://github.com/openai/openai-node/issues/1397)) ([7c3d212](https://github.com/openai/openai-node/commit/7c3d212b47ee3090f5bbb82dd21026ba532da6e0)) +* fix example types ([20f179d](https://github.com/openai/openai-node/commit/20f179db1bb681db5d1a91adcaab16012d6ffcdf)) +* improve publish-npm script --latest tag logic ([6d3cc5c](https://github.com/openai/openai-node/commit/6d3cc5c99ba005c39a1550b30c4243ba454b9cb1)) +* improve publish-npm script --latest tag logic ([1f59811](https://github.com/openai/openai-node/commit/1f59811d1c5616ff949e01cb2f90cfc62fdefc7e)) +* improve publish-npm script --latest tag logic ([6207a2a](https://github.com/openai/openai-node/commit/6207a2a03d3279423de594eed18c5efb4ce321af)) +* **internal:** add aliases for Record and Array ([8957ff4](https://github.com/openai/openai-node/commit/8957ff47e6dc6cbaf750482c76929e99e5eca48c)) +* **internal:** add aliases for Record and Array ([#1443](https://github.com/openai/openai-node/issues/1443)) ([1cb66b6](https://github.com/openai/openai-node/commit/1cb66b6ccbcecaa6e48b90d37d8cac4840bb69a4)) +* **internal:** add back release workflow ([ca6266e](https://github.com/openai/openai-node/commit/ca6266eea5229056a3bc2b5e4225b9ea9eaa459e)) +* **internal:** add Bun.File ecosystem test ([cb4194f](https://github.com/openai/openai-node/commit/cb4194f08a2dcb4fc4231bf1b74ed5d6e0aca435)) +* **internal:** add missing return type annotation ([00ce31b](https://github.com/openai/openai-node/commit/00ce31bb6248002b0e575db2dfdd5c4bbbbcb37d)) +* **internal:** add missing return type annotation ([#1334](https://github.com/openai/openai-node/issues/1334)) ([13aab10](https://github.com/openai/openai-node/commit/13aab101588c2eee1250d7c50b2abfeca1c5fa3d)) +* **internal:** add proxy ecosystem tests ([619711a](https://github.com/openai/openai-node/commit/619711ae0da5243c64c266d615703279f7651f58)) +* **internal:** bump migration cli version ([a899c97](https://github.com/openai/openai-node/commit/a899c9748de17ef468a03a97b9ed82124189ff4c)) +* **internal:** codegen related update ([fa48353](https://github.com/openai/openai-node/commit/fa48353ffd03bfa2fb81ee16a9fb5fae0b0073c1)) +* **internal:** codegen related update ([c735a3c](https://github.com/openai/openai-node/commit/c735a3c24ac8255df50f89c519fb7dfc617db045)) +* **internal:** fix devcontainers setup ([873e273](https://github.com/openai/openai-node/commit/873e273b8c4e4e7f45feec466896b7e5ce0d8577)) +* **internal:** fix devcontainers setup ([#1343](https://github.com/openai/openai-node/issues/1343)) ([9485f5d](https://github.com/openai/openai-node/commit/9485f5d4d6718bff7f579223c9aa528898451533)) +* **internal:** fix eslint ignores ([ad5a9b6](https://github.com/openai/openai-node/commit/ad5a9b6f07002df70764f1b9e5d6cd675eba87ea)) +* **internal:** fix examples ([db23ff3](https://github.com/openai/openai-node/commit/db23ff3a179229557de07eefcda879492435b572)) +* **internal:** fix examples ([#1457](https://github.com/openai/openai-node/issues/1457)) ([a100f0a](https://github.com/openai/openai-node/commit/a100f0a0e1d336f8a78c8bbd9e3703cda3f0c5d8)) +* **internal:** fix format script ([3e1ea40](https://github.com/openai/openai-node/commit/3e1ea4063327ac34f4f46536600a8923f96dbbb0)) +* **internal:** fix formatting ([6469d53](https://github.com/openai/openai-node/commit/6469d5323b653f19e90a7470d81c914c640c6f8b)) +* **internal:** fix lint ([45a372c](https://github.com/openai/openai-node/commit/45a372ca0436f2f79c2387665b1c1bc04fd3bfed)) +* **internal:** fix release workflows ([0e4b982](https://github.com/openai/openai-node/commit/0e4b98261e412417dd0f6d1c799ef77398bfb7c0)) +* **internal:** fix release workflows ([353349d](https://github.com/openai/openai-node/commit/353349de9ee10d32d3243cb5c60a8ae982c49d37)) +* **internal:** fix tests failing on node v18 ([c54270a](https://github.com/openai/openai-node/commit/c54270a58ada1d0d7878ce80c7c2093a56fed158)) +* **internal:** fix tests not always being type checked ([0266b41](https://github.com/openai/openai-node/commit/0266b41efa311205f0fc51b6dc6d29ab003254a6)) +* **internal:** improve node 18 shims ([ee3f483](https://github.com/openai/openai-node/commit/ee3f48333a1d73a096f3417b2701fd722e4fbc68)) +* **internal:** minor client file refactoring ([d1aa00a](https://github.com/openai/openai-node/commit/d1aa00afc760f73624a8a109600c03deba40e72b)) +* **internal:** only run examples workflow in main repo ([#1450](https://github.com/openai/openai-node/issues/1450)) ([93569f3](https://github.com/openai/openai-node/commit/93569f39799512604db439af20f0ef0ad3dae295)) +* **internal:** reduce CI branch coverage ([bb39dba](https://github.com/openai/openai-node/commit/bb39dbae2830f64ede70f0ae1cea2935d1720911)) +* **internal:** reduce CI branch coverage ([77fc77f](https://github.com/openai/openai-node/commit/77fc77f7d05d03eafe6c8f002044c60c4bab3c64)) +* **internal:** refactor utils ([e7fbfbc](https://github.com/openai/openai-node/commit/e7fbfbce41c00aaa7d3b75a4bf001c7562b5b722)) +* **internal:** remove CI condition ([ef43345](https://github.com/openai/openai-node/commit/ef43345f0828a5313b595ed1715094d110f2f44e)) +* **internal:** remove CI condition ([#1381](https://github.com/openai/openai-node/issues/1381)) ([e905c95](https://github.com/openai/openai-node/commit/e905c95a27213ee65210b061ead4c982de01648b)) +* **internal:** remove unnecessary todo ([b55321e](https://github.com/openai/openai-node/commit/b55321e2d0713d41b4050e8ccf0ac4eefb45be3a)) +* **internal:** run CI on update-specs branch ([9c45ef3](https://github.com/openai/openai-node/commit/9c45ef37249e7db3ba8aa2e81886ffe306b95da4)) +* **internal:** run example files in CI ([#1357](https://github.com/openai/openai-node/issues/1357)) ([1044c48](https://github.com/openai/openai-node/commit/1044c487566569e773d5f6c1a94ce6b614e62b80)) +* **internal:** share typescript helpers ([2470933](https://github.com/openai/openai-node/commit/247093374538f0e714178134c38813bc4fde9ecf)) +* **internal:** skip broken test ([5b81f62](https://github.com/openai/openai-node/commit/5b81f62ac12969cf0a6da8bf0bfde81ff025e092)) +* **internal:** skip broken test ([#1458](https://github.com/openai/openai-node/issues/1458)) ([58f4559](https://github.com/openai/openai-node/commit/58f4559d952f6e56a8f27a6bcaba0acf295623df)) +* **internal:** update @types/bun ([d94b41a](https://github.com/openai/openai-node/commit/d94b41a58e24c82c3f7369bd1360b394e93cf1dd)) +* **internal:** update release workflows ([2cbf49a](https://github.com/openai/openai-node/commit/2cbf49a0b9a8cfbee29cec558c5ccdcebd72396f)) +* **internal:** upload builds and expand CI branch coverage ([3dcbe17](https://github.com/openai/openai-node/commit/3dcbe171d4d2a93e645828b39395363f064136b0)) +* **internal:** upload builds and expand CI branch coverage ([#1460](https://github.com/openai/openai-node/issues/1460)) ([2d45287](https://github.com/openai/openai-node/commit/2d452879000c07f3ef4e775e19a527f5f6fa7b4c)) +* **internal:** version bump ([b40e830](https://github.com/openai/openai-node/commit/b40e8302ec11683b6a360a050236ad1284afc760)) +* **internal:** version bump ([5123fe0](https://github.com/openai/openai-node/commit/5123fe08a56f3d0040b1cc67129382f3eacc3cca)) +* **internal:** version bump ([#1393](https://github.com/openai/openai-node/issues/1393)) ([2e49526](https://github.com/openai/openai-node/commit/2e495267329b6853edff76c415e4c5ddc5e143e8)) +* **migration:** add beta handling ([3508099](https://github.com/openai/openai-node/commit/3508099991ecfa260d77678037275133130e09dc)) +* move ChatModel type to shared ([236dbf4](https://github.com/openai/openai-node/commit/236dbf4092fccf7697852c6341a8f38f0241770c)) +* **package:** remove engines ([500a82f](https://github.com/openai/openai-node/commit/500a82f45d46697be14987e12d896acb2b109d32)) +* **perf:** faster base64 decoding ([11b9534](https://github.com/openai/openai-node/commit/11b9534d317f87cdcb1934ead013f058865e675e)) +* Remove deprecated/unused remote spec feature ([00bdda3](https://github.com/openai/openai-node/commit/00bdda332097787a1b09ef903b3304d3e61cde1c)) +* Remove deprecated/unused remote spec feature ([71950f6](https://github.com/openai/openai-node/commit/71950f6e891ba0813c25b2992db93a61ef6c9664)) +* revert temporary version change ([47a8350](https://github.com/openai/openai-node/commit/47a83508645b0b5a0e4bf994f753c5752717fdc2)) +* **tests:** improve enum examples ([0b30331](https://github.com/openai/openai-node/commit/0b30331a7e89ed9c400bb1b9ebfb33867a00f8bd)) +* **tests:** improve enum examples ([#1454](https://github.com/openai/openai-node/issues/1454)) ([15a86c9](https://github.com/openai/openai-node/commit/15a86c958bf300486907f2498e1028fc9bc50b00)) +* **tests:** stop using node-fetch, don't directly upload FormDataFile ([ebd464f](https://github.com/openai/openai-node/commit/ebd464f5ad07f440ad476c0a7ce733947da414e2)) +* **tests:** switch proxy tests to fetchOptions ([da6ed5f](https://github.com/openai/openai-node/commit/da6ed5fc4c9ec203d9add28c34c90532b0334a3e)) +* **types:** improved go to definition on fetchOptions ([f1712cd](https://github.com/openai/openai-node/commit/f1712cdea42e9d95d4b2dc40aae5cebc8e14c76d)) +* update next to 14.2.25 for CVE-2025-29927 ([1ed4288](https://github.com/openai/openai-node/commit/1ed4288c7b9ca8fcb00e524bc6f39c255c6661c5)) +* workaround build errors ([e4a7f67](https://github.com/openai/openai-node/commit/e4a7f674f719a87bb78378a5ce4639d84620e17a)) +* workaround build errors ([d6b396b](https://github.com/openai/openai-node/commit/d6b396b94d9ccf64ddfe945069012b6162225fa9)) + + +### Documentation + +* add examples to tsdocs ([e8d2092](https://github.com/openai/openai-node/commit/e8d2092e51015b05fe7ef33ef5a9d7652846b137)) +* fix "procesing" -> "processing" in realtime examples ([#1406](https://github.com/openai/openai-node/issues/1406)) ([dfbdc65](https://github.com/openai/openai-node/commit/dfbdc65d3ed17f0063d02906239371b88e04e5fd)) +* **migration:** mention function renames ([eb773ee](https://github.com/openai/openai-node/commit/eb773ee26df88ab6da5918521c5e979860a5aaee)) +* **migration:** mention zod helpers error ([43b870d](https://github.com/openai/openai-node/commit/43b870d1651d0c13e4ec10a53de2dfbae276c3e7)) +* **readme:** fix typo ([c44ed98](https://github.com/openai/openai-node/commit/c44ed98a3e7f497a656d612037667dd1f2e6816b)) +* **readme:** fix typo ([0989ddc](https://github.com/openai/openai-node/commit/0989ddcfd5ed0a149bbc67d61f93e0f49c397c72)) +* update URLs from stainlessapi.com to stainless.com ([e4e737d](https://github.com/openai/openai-node/commit/e4e737d90718d077c266e4c382a1535fc4bf1c69)) +* update URLs from stainlessapi.com to stainless.com ([#1352](https://github.com/openai/openai-node/issues/1352)) ([634a209](https://github.com/openai/openai-node/commit/634a209a6025640e2849133f6997af8faa28d4d8)) + + +### Refactors + +* **client:** remove deprecated runFunctions method ([e29a009](https://github.com/openai/openai-node/commit/e29a0092e9b077c2a99cd521a316aea4c25ea632)) +* **functions:** rename function helper methods to include tools ([fdd6f66](https://github.com/openai/openai-node/commit/fdd6f6672ec577cbb6876fe3857a2161402513c3)) + ## 4.104.0 (2025-05-29) Full Changelog: [v4.103.0...v4.104.0](https://github.com/openai/openai-node/compare/v4.103.0...v4.104.0) diff --git a/MIGRATION.md b/MIGRATION.md new file mode 100644 index 000000000..9d48435e3 --- /dev/null +++ b/MIGRATION.md @@ -0,0 +1,538 @@ +# 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. + +## Migration CLI + +Most programs will only need minimal changes, but to assist there is a migration tool that will automatically update your code for the new version. +To use it, upgrade the `openai` package, then run `./node_modules/.bin/openai migrate ./your/src/folders` to update your code. +To preview the changes without writing them to disk, run the tool with `--dry`. + +## Environment requirements + +The minimum supported runtime and tooling versions are now: + +- Node.js 20 LTS (Most recent non-EOL Node version) +- TypeScript 4.9 +- Jest 28 + +## Breaking changes + +### Web types for `withResponse`, `asResponse`, and `APIError.headers` + +Because we now use the builtin Web fetch API on all platforms, if you wrote code that used `withResponse` or `asResponse` and then accessed `node-fetch`-specific properties on the result, you will need to switch to standardized alternatives. +For example, `body` is now a [Web `ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream) rather than a [node `Readable`](https://nodejs.org/api/stream.html#readable-streams). + +```ts +// Before: +const res = await client.example.retrieve('string/with/slash').asResponse(); +res.body.pipe(process.stdout); + +// After: +import { Readable } from 'node:stream'; +const res = await client.example.retrieve('string/with/slash').asResponse(); +Readable.fromWeb(res.body).pipe(process.stdout); +``` + +Additionally, 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 defined as `Record`. + +### 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.retrieve('p_123', 'c_456'); + +// After +client.parents.children.retrieve('c_456', { parent_id: 'p_123' }); +``` + +
+ +This affects the following methods + +- `client.fineTuning.checkpoints.permissions.delete()` +- `client.vectorStores.files.retrieve()` +- `client.vectorStores.files.update()` +- `client.vectorStores.files.delete()` +- `client.vectorStores.files.content()` +- `client.vectorStores.fileBatches.retrieve()` +- `client.vectorStores.fileBatches.cancel()` +- `client.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()` +- `client.evals.runs.retrieve()` +- `client.evals.runs.delete()` +- `client.evals.runs.cancel()` +- `client.evals.runs.outputItems.retrieve()` +- `client.evals.runs.outputItems.list()` +- `client.containers.files.retrieve()` +- `client.containers.files.delete()` +- `client.containers.files.content.retrieve()` + +
+ +### 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') // retrieves /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 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.fineTuning.checkpoints.permissions.retrieve()` +- `client.vectorStores.list()` +- `client.vectorStores.files.list()` +- `client.beta.assistants.list()` +- `client.beta.threads.create()` +- `client.beta.threads.runs.list()` +- `client.beta.threads.messages.list()` +- `client.batches.list()` +- `client.responses.retrieve()` +- `client.responses.inputItems.list()` +- `client.evals.list()` +- `client.evals.runs.list()` +- `client.containers.list()` +- `client.containers.files.list()` + +### HTTP method naming + +Previously some methods could not be named intuitively due to an internal naming conflict. This has been fixed and the affected methods are now correctly named. + +```ts +// Before +client.chat.completions.del(); +client.files.del(); +client.models.del(); +client.fineTuning.checkpoints.permissions.del(); +client.vectorStores.del(); +client.vectorStores.files.del(); +client.beta.assistants.del(); +client.beta.threads.del(); +client.beta.threads.messages.del(); +client.responses.del(); +client.evals.del(); +client.evals.runs.del(); +client.containers.del(); +client.containers.files.del(); + +// After +client.chat.completions.delete(); +client.files.delete(); +client.models.delete(); +client.fineTuning.checkpoints.permissions.delete(); +client.vectorStores.delete(); +client.vectorStores.files.delete(); +client.beta.assistants.delete(); +client.beta.threads.delete(); +client.beta.threads.messages.delete(); +client.responses.delete(); +client.evals.delete(); +client.evals.runs.delete(); +client.containers.delete(); +client.containers.files.delete(); +``` + +### 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, + }, +}); +``` + +### Changed exports + +#### Refactor of `openai/core`, `error`, `pagination`, `resource`, `streaming` and `uploads` + +Much of 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 and public files, with public-facing code moved to a new `core` folder and internal code moving to the private `internal` folder. + +At the same time, we moved some public-facing files which were previously at the top level into `core` to make the file structure cleaner and more clear: + +```typescript +// Before +import 'openai/error'; +import 'openai/pagination'; +import 'openai/resource'; +import 'openai/streaming'; +import 'openai/uploads'; + +// After +import 'openai/core/error'; +import 'openai/core/pagination'; +import 'openai/core/resource'; +import 'openai/core/streaming'; +import 'openai/core/uploads'; +``` + +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. + +#### Resource classes + +Previously under certain circumstances it was possible to import resource classes like `Completions` directly from the root of the package. This was never valid at the type level and only worked in CommonJS files. +Now you must always either reference them as static class properties or import them directly from the files in which they are defined. + +```typescript +// Before +const { Completions } = require('openai'); + +// After +const { OpenAI } = require('openai'); +OpenAI.Completions; // or import directly from openai/resources/completions +``` + +#### Cleaned up `uploads` exports + +As part of the `core` refactor, `openai/uploads` was moved to `openai/core/uploads` +and the following exports were removed, 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/core/uploads'; +``` + +#### `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'; +``` + +### 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.js. 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). + +### Zod helpers optionality error + +Previously, the following code would just output a warning to the console, now it will throw an error. + +```ts +const completion = await client.chat.completions.parse({ + // ... + response_format: zodResponseFormat( + z.object({ + optional_property: z.string().optional(), + }), + 'schema', + ), +}); +``` + +You must mark optional properties with `.nullable()` as purely optional fields are not supported by the [API](https://platform.openai.com/docs/guides/structured-outputs?api-mode=responses#all-fields-must-be-required). + +```ts +const completion = await client.chat.completions.parse({ + // ... + response_format: zodResponseFormat( + z.object({ + optional_property: z.string().optional().nullable(), + }), + 'schema', + ), +}); +``` + +### Pagination changes + +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); +} +``` + +The interface for manually paginating through list results 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. + +### Beta chat namespace removed + +The `beta.chat` namespace has been removed. All chat completion methods that were previously in beta have been moved to the main `chat.completions` namespace: + +```ts +// Before +client.beta.chat.completions.parse() +client.beta.chat.completions.stream() +client.beta.chat.completions.runTools() + +// After +client.chat.completions.parse() +client.chat.completions.stream() +client.chat.completions.runTools() +``` + +Additionally, related types have been moved: + +```ts +// Before +import { ParsedChatCompletion, ParsedChoice, ParsedFunction } from 'openai/resources/beta/chat/completions'; + +// After +import { ParsedChatCompletion, ParsedChoice, ParsedFunction } from 'openai/resources/chat/completions'; +``` + +### Removed deprecated `.runFunctions` methods + +The deprecated `client.chat.completions.runFunctions()` method and all of it's surrounding types have been removed, instead you should use +`client.chat.completions.runTools()`. + +### `.runTools()` event / method names + +To better align with the tool-based API, several event names in the ChatCompletionRunner have been renamed: + +```ts +// Before +openai.chat.completions + .runTools({ + // .. + }) + .on('functionCall', (functionCall) => console.log('functionCall', functionCall)) + .on('functionCallResult', (functionCallResult) => console.log('functionCallResult', functionCallResult)) + .on('finalFunctionCall', (functionCall) => console.log('finalFunctionCall', functionCall)) + .on('finalFunctionCallResult', (result) => console.log('finalFunctionCallResult', result)); + +// After +openai.chat.completions + .runTools({ + // .. + }) + .on('functionToolCall', (functionCall) => console.log('functionCall', functionCall)) + .on('functionToolCallResult', (functionCallResult) => console.log('functionCallResult', functionCallResult)) + .on('finalFunctionToolCall', (functionCall) => console.log('finalFunctionCall', functionCall)) + .on('finalFunctionToolCallResult', (result) => console.log('finalFunctionCallResult', result)); +``` + +The following event names have been changed: +- `functionCall` → `functionToolCall` +- `functionCallResult` → `functionToolCallResult` +- `finalFunctionCall` → `finalFunctionToolCall` +- `finalFunctionCallResult` → `finalFunctionToolCallResult` + +Additionally, the following methods have been renamed: +- `runner.finalFunctionCall()` → `runner.finalFunctionToolCall()` +- `runner.finalFunctionCallResult()` → `runner.finalFunctionToolCallResult()` + +### `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 will need to replace them with `openai/*`. + +```ts +// Before +import OpenAI from 'openai/src'; + +// After +import OpenAI from 'openai'; +``` + +## TypeScript troubleshooting + +When referencing the library after updating, you may encounter new type errors related to JS features like private properties or fetch classes like Request, Response, and Headers. +To resolve these issues, configure your tsconfig.json and install the appropriate `@types` packages for your runtime environment using the guidelines below: + +### Browsers + +`tsconfig.json` + +```jsonc +{ + "target": "ES2018", // note: we recommend ES2020 or higher + "lib": ["DOM", "DOM.Iterable", "ES2018"] +} +``` + +### Node.js + +`tsconfig.json` + +```jsonc +{ + "target": "ES2018" // note: we recommend ES2020 or higher +} +``` + +`package.json` + +```json +{ + "devDependencies": { + "@types/node": ">= 20" + } +} +``` + +### Cloudflare Workers + +`tsconfig.json` + +```jsonc +{ + "target": "ES2018", // 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": "ES2018" // note: we recommend ES2020 or higher +} +``` + +`package.json` + +```json +{ + "devDependencies": { + "@types/bun": ">= 1.2.0" + } +} +``` diff --git a/README.md b/README.md index bbf72226a..0f4449006 100644 --- a/README.md +++ b/README.md @@ -100,7 +100,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(); @@ -164,6 +163,73 @@ Error codes are as follows: | >=500 | `InternalServerError` | | N/A | `APIConnectionError` | +## Request IDs + +> For more information on debugging requests, see [these docs](https://platform.openai.com/docs/api-reference/debugging-requests) + +All object responses in the SDK provide a `_request_id` property which is added from the `x-request-id` response header so that you can quickly log failing requests and report them back to OpenAI. + +```ts +const completion = await client.chat.completions.create({ + messages: [{ role: 'user', content: 'Say this is a test' }], + model: 'gpt-4o', +}); +console.log(completion._request_id); // req_123 +``` + +You can also access the Request ID using the `.withResponse()` method: + +```ts +const { data: stream, request_id } = await openai.chat.completions + .create({ + model: 'gpt-4', + messages: [{ role: 'user', content: 'Say this is a test' }], + stream: true, + }) + .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` +class instead of the `OpenAI` class. + +> [!IMPORTANT] +> The Azure API shape slightly differs from the core API shape which means that the static types for responses / params +> won't always be correct. + +```ts +import { AzureOpenAI } from 'openai'; +import { getBearerTokenProvider, DefaultAzureCredential } from '@azure/identity'; + +const credential = new DefaultAzureCredential(); +const scope = 'https://cognitiveservices.azure.com/.default'; +const azureADTokenProvider = getBearerTokenProvider(credential, scope); + +const openai = new AzureOpenAI({ azureADTokenProvider }); + +const result = await openai.chat.completions.create({ + model: 'gpt-4o', + messages: [{ role: 'user', content: 'Say hello!' }], +}); + +console.log(result.choices[0]!.message?.content); +``` + ### Retries Certain errors will be automatically retried 2 times by default, with a short exponential backoff. @@ -214,7 +280,7 @@ All object responses in the SDK provide a `_request_id` property which is added ```ts const response = await client.responses.create({ model: 'gpt-4o', input: 'testing 123' }); -console.log(response._request_id) // req_123 +console.log(response._request_id); // req_123 ``` You can also access the Request ID using the `.withResponse()` method: @@ -291,7 +357,10 @@ const credential = new DefaultAzureCredential(); const scope = 'https://cognitiveservices.azure.com/.default'; const azureADTokenProvider = getBearerTokenProvider(credential, scope); -const openai = new AzureOpenAI({ azureADTokenProvider, apiVersion: "" }); +const openai = new AzureOpenAI({ + azureADTokenProvider, + apiVersion: '', +}); const result = await openai.chat.completions.create({ model: 'gpt-4o', @@ -308,8 +377,10 @@ For more information on support for the Azure API, see [azure.md](azure.md). ### Accessing raw Response data (e.g., headers) The "raw" `Response` returned by `fetch()` can be accessed through the `.asResponse()` method on the `APIPromise` type that all methods return. +This method returns as soon as the headers for a successful response are received and does not consume the response body, so you are free to write custom parsing or streaming logic. You can also use the `.withResponse()` method to get the raw `Response` along with the parsed data. +Unlike `.asResponse()` this method consumes the body, returning once it is parsed. ```ts @@ -330,6 +401,59 @@ console.log(raw.headers.get('X-My-Header')); console.log(modelResponse); ``` +### 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 @@ -376,71 +500,83 @@ validate or strip extra properties from the response from the API. ### Customizing the fetch client -> We're actively working on a new alpha version that migrates from `node-fetch` to builtin fetch. -> -> Please try it out and let us know if you run into any issues! -> https://community.openai.com/t/your-feedback-requested-node-js-sdk-5-0-0-alpha/1063774 +If you want to use a different `fetch` function, you can either polyfill the global: -By default, this library uses `node-fetch` in Node, and expects a global `fetch` function in other environments. +```ts +import fetch from 'my-fetch'; -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"`: +globalThis.fetch = fetch; +``` + +Or pass it to the client: ```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'; -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)). +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: @@ -455,11 +591,11 @@ 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: -- Node.js 18 LTS or later ([non-EOL](https://endoflife.date/nodejs)) versions. +- Node.js 20 LTS or later ([non-EOL](https://endoflife.date/nodejs)) versions. - Deno v1.28.0 or higher. - Bun 1.0 or later. - Cloudflare Workers. diff --git a/api.md b/api.md index 86d6435dd..c367a06f0 100644 --- a/api.md +++ b/api.md @@ -68,22 +68,21 @@ Types: - ChatCompletionToolChoiceOption - ChatCompletionToolMessageParam - ChatCompletionUserMessageParam -- CreateChatCompletionRequestMessage - ChatCompletionReasoningEffort Methods: - client.chat.completions.create({ ...params }) -> ChatCompletion -- client.chat.completions.retrieve(completionId) -> ChatCompletion -- client.chat.completions.update(completionId, { ...params }) -> ChatCompletion +- client.chat.completions.retrieve(completionID) -> ChatCompletion +- client.chat.completions.update(completionID, { ...params }) -> ChatCompletion - client.chat.completions.list({ ...params }) -> ChatCompletionsPage -- client.chat.completions.del(completionId) -> ChatCompletionDeleted +- client.chat.completions.delete(completionID) -> ChatCompletionDeleted ### Messages Methods: -- client.chat.completions.messages.list(completionId, { ...params }) -> ChatCompletionStoreMessagesPage +- client.chat.completions.messages.list(completionID, { ...params }) -> ChatCompletionStoreMessagesPage # Embeddings @@ -109,11 +108,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 @@ -203,7 +201,7 @@ Methods: - client.models.retrieve(model) -> Model - client.models.list() -> ModelsPage -- client.models.del(model) -> ModelDeleted +- client.models.delete(model) -> ModelDeleted # FineTuning @@ -224,19 +222,19 @@ Types: - FineTuningJob - FineTuningJobEvent -- FineTuningJobIntegration - FineTuningJobWandbIntegration - FineTuningJobWandbIntegrationObject +- FineTuningJobIntegration 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.pause(fineTuningJobId) -> FineTuningJob -- client.fineTuning.jobs.resume(fineTuningJobId) -> FineTuningJob +- client.fineTuning.jobs.cancel(fineTuningJobID) -> FineTuningJob +- client.fineTuning.jobs.listEvents(fineTuningJobID, { ...params }) -> FineTuningJobEventsPage +- client.fineTuning.jobs.pause(fineTuningJobID) -> FineTuningJob +- client.fineTuning.jobs.resume(fineTuningJobID) -> FineTuningJob ### Checkpoints @@ -246,7 +244,7 @@ Types: Methods: -- client.fineTuning.jobs.checkpoints.list(fineTuningJobId, { ...params }) -> FineTuningJobCheckpointsPage +- client.fineTuning.jobs.checkpoints.list(fineTuningJobID, { ...params }) -> FineTuningJobCheckpointsPage ## Checkpoints @@ -262,7 +260,7 @@ Methods: - client.fineTuning.checkpoints.permissions.create(fineTunedModelCheckpoint, { ...params }) -> PermissionCreateResponsesPage - client.fineTuning.checkpoints.permissions.retrieve(fineTunedModelCheckpoint, { ...params }) -> PermissionRetrieveResponse -- client.fineTuning.checkpoints.permissions.del(fineTunedModelCheckpoint, permissionId) -> PermissionDeleteResponse +- client.fineTuning.checkpoints.permissions.delete(permissionID, { ...params }) -> PermissionDeleteResponse ## Alpha @@ -309,11 +307,11 @@ Types: Methods: - client.vectorStores.create({ ...params }) -> VectorStore -- client.vectorStores.retrieve(vectorStoreId) -> VectorStore -- client.vectorStores.update(vectorStoreId, { ...params }) -> VectorStore +- client.vectorStores.retrieve(vectorStoreID) -> VectorStore +- client.vectorStores.update(vectorStoreID, { ...params }) -> VectorStore - client.vectorStores.list({ ...params }) -> VectorStoresPage -- client.vectorStores.del(vectorStoreId) -> VectorStoreDeleted -- client.vectorStores.search(vectorStoreId, { ...params }) -> VectorStoreSearchResponsesPage +- client.vectorStores.delete(vectorStoreID) -> VectorStoreDeleted +- client.vectorStores.search(vectorStoreID, { ...params }) -> VectorStoreSearchResponsesPage ## Files @@ -331,10 +329,10 @@ Methods: - client.vectorStores.files.list(vectorStoreId, { ...params }) -> VectorStoreFilesPage - client.vectorStores.files.del(vectorStoreId, fileId) -> VectorStoreFileDeleted - client.vectorStores.files.content(vectorStoreId, fileId) -> FileContentResponsesPage -- 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> -- client.beta.vectorStores.files.uploadAndPoll(vectorStoreId, file, options?) -> Promise<VectorStoreFile> +- client.vectorStores.files.createAndPoll(vectorStoreId, body, options?) -> Promise<VectorStoreFile> +- client.vectorStores.files.poll(vectorStoreId, fileId, options?) -> Promise<VectorStoreFile> +- client.vectorStores.files.upload(vectorStoreId, file, options?) -> Promise<VectorStoreFile> +- client.vectorStores.files.uploadAndPoll(vectorStoreId, file, options?) -> Promise<VectorStoreFile> ## FileBatches @@ -344,13 +342,14 @@ Types: Methods: -- client.vectorStores.fileBatches.create(vectorStoreId, { ...params }) -> VectorStoreFileBatch -- client.vectorStores.fileBatches.retrieve(vectorStoreId, batchId) -> VectorStoreFileBatch -- client.vectorStores.fileBatches.cancel(vectorStoreId, batchId) -> VectorStoreFileBatch -- client.vectorStores.fileBatches.listFiles(vectorStoreId, 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> +- client.vectorStores.fileBatches.create(vectorStoreID, { ...params }) -> VectorStoreFileBatch +- client.vectorStores.fileBatches.retrieve(batchID, { ...params }) -> VectorStoreFileBatch +- client.vectorStores.fileBatches.cancel(batchID, { ...params }) -> VectorStoreFileBatch +- client.vectorStores.fileBatches.listFiles(batchID, { ...params }) -> VectorStoreFilesPage +- client.vectorStores.files.createAndPoll(vectorStoreId, body, options?) -> Promise<VectorStoreFile> +- client.vectorStores.files.poll(vectorStoreId, fileId, options?) -> Promise<VectorStoreFile> +- client.vectorStores.files.upload(vectorStoreId, file, options?) -> Promise<VectorStoreFile> +- client.vectorStores.files.uploadAndPoll(vectorStoreId, file, options?) -> Promise<VectorStoreFile> # Beta @@ -448,10 +447,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 @@ -467,9 +466,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 @@ -484,12 +483,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> @@ -522,8 +521,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 @@ -560,11 +559,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 @@ -577,9 +576,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 @@ -590,8 +589,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 @@ -601,7 +600,7 @@ Types: Methods: -- client.uploads.parts.create(uploadId, { ...params }) -> UploadPart +- client.uploads.parts.create(uploadID, { ...params }) -> UploadPart # Responses @@ -708,9 +707,9 @@ Types: Methods: - client.responses.create({ ...params }) -> Response -- client.responses.retrieve(responseId, { ...params }) -> Response -- client.responses.del(responseId) -> void -- client.responses.cancel(responseId) -> void +- client.responses.retrieve(responseID, { ...params }) -> Response +- client.responses.delete(responseID) -> void +- client.responses.cancel(responseID) -> void ## InputItems @@ -720,7 +719,7 @@ Types: Methods: -- client.responses.inputItems.list(responseId, { ...params }) -> ResponseItemsPage +- client.responses.inputItems.list(responseID, { ...params }) -> ResponseItemsPage # Evals @@ -737,10 +736,10 @@ Types: Methods: - client.evals.create({ ...params }) -> EvalCreateResponse -- client.evals.retrieve(evalId) -> EvalRetrieveResponse -- client.evals.update(evalId, { ...params }) -> EvalUpdateResponse +- client.evals.retrieve(evalID) -> EvalRetrieveResponse +- client.evals.update(evalID, { ...params }) -> EvalUpdateResponse - client.evals.list({ ...params }) -> EvalListResponsesPage -- client.evals.del(evalId) -> EvalDeleteResponse +- client.evals.delete(evalID) -> EvalDeleteResponse ## Runs @@ -757,11 +756,11 @@ Types: Methods: -- client.evals.runs.create(evalId, { ...params }) -> RunCreateResponse -- client.evals.runs.retrieve(evalId, runId) -> RunRetrieveResponse -- client.evals.runs.list(evalId, { ...params }) -> RunListResponsesPage -- client.evals.runs.del(evalId, runId) -> RunDeleteResponse -- client.evals.runs.cancel(evalId, runId) -> RunCancelResponse +- client.evals.runs.create(evalID, { ...params }) -> RunCreateResponse +- client.evals.runs.retrieve(runID, { ...params }) -> RunRetrieveResponse +- client.evals.runs.list(evalID, { ...params }) -> RunListResponsesPage +- client.evals.runs.delete(runID, { ...params }) -> RunDeleteResponse +- client.evals.runs.cancel(runID, { ...params }) -> RunCancelResponse ### OutputItems @@ -772,8 +771,8 @@ Types: Methods: -- client.evals.runs.outputItems.retrieve(evalId, runId, outputItemId) -> OutputItemRetrieveResponse -- client.evals.runs.outputItems.list(evalId, runId, { ...params }) -> OutputItemListResponsesPage +- client.evals.runs.outputItems.retrieve(outputItemID, { ...params }) -> OutputItemRetrieveResponse +- client.evals.runs.outputItems.list(runID, { ...params }) -> OutputItemListResponsesPage # Containers @@ -786,9 +785,9 @@ Types: Methods: - client.containers.create({ ...params }) -> ContainerCreateResponse -- client.containers.retrieve(containerId) -> ContainerRetrieveResponse +- client.containers.retrieve(containerID) -> ContainerRetrieveResponse - client.containers.list({ ...params }) -> ContainerListResponsesPage -- client.containers.del(containerId) -> void +- client.containers.delete(containerID) -> void ## Files @@ -800,13 +799,13 @@ Types: Methods: -- client.containers.files.create(containerId, { ...params }) -> FileCreateResponse -- client.containers.files.retrieve(containerId, fileId) -> FileRetrieveResponse -- client.containers.files.list(containerId, { ...params }) -> FileListResponsesPage -- client.containers.files.del(containerId, fileId) -> void +- client.containers.files.create(containerID, { ...params }) -> FileCreateResponse +- client.containers.files.retrieve(fileID, { ...params }) -> FileRetrieveResponse +- client.containers.files.list(containerID, { ...params }) -> FileListResponsesPage +- client.containers.files.delete(fileID, { ...params }) -> void ### Content Methods: -- client.containers.files.content.retrieve(containerId, fileId) -> Response +- client.containers.files.content.retrieve(fileID, { ...params }) -> Response diff --git a/azure.md b/azure.md index df06c2985..aa982acd0 100644 --- a/azure.md +++ b/azure.md @@ -15,7 +15,10 @@ const credential = new DefaultAzureCredential(); const scope = 'https://cognitiveservices.azure.com/.default'; const azureADTokenProvider = getBearerTokenProvider(credential, scope); -const openai = new AzureOpenAI({ azureADTokenProvider, apiVersion: "" }); +const openai = new AzureOpenAI({ + azureADTokenProvider, + apiVersion: '', +}); const result = await openai.chat.completions.create({ model: 'gpt-4o', diff --git a/bin/cli b/bin/cli index 00275ace4..0bbffe6ba 100755 --- a/bin/cli +++ b/bin/cli @@ -4,25 +4,28 @@ const { spawnSync } = require('child_process'); const commands = { migrate: { - description: 'Run migrations to update from openai v3 to v4', + description: 'Run migrations to update to the latest major SDK version', fn: () => { - console.log('This automatic code migration is provided by grit.io'); - console.log('Visit https://app.grit.io/studio?preset=openai_v4 for more details.') - const result = spawnSync( 'npx', - ['-y', '@getgrit/launcher', 'apply', 'openai_v4', ...process.argv.slice(3)], + [ + '-y', + 'https://github.com/stainless-api/migrate-ts/releases/download/0.0.3/stainless-api-migrate-0.0.3.tgz', + '--migrationConfig', + require.resolve('./migration-config.json'), + ...process.argv.slice(3), + ], { stdio: 'inherit' }, ); if (result.status !== 0) { process.exit(result.status); } - } - } -} + }, + }, +}; function exitWithHelp() { - console.log("Usage: $0 "); + console.log(`Usage: openai `); console.log(); console.log('Subcommands:'); diff --git a/bin/migration-config.json b/bin/migration-config.json new file mode 100644 index 000000000..26d644698 --- /dev/null +++ b/bin/migration-config.json @@ -0,0 +1,939 @@ +{ + "pkg": "openai", + "githubRepo": "https://github.com/stainless-sdks/openai-typescript", + "clientClass": "OpenAI", + "methods": [ + { + "base": "chat.completions", + "name": "delete", + "oldName": "del" + }, + { + "base": "chat.completions", + "name": "stream", + "oldBase": "beta.chat.completions" + }, + { + "base": "chat.completions", + "name": "parse", + "oldBase": "beta.chat.completions" + }, + { + "base": "chat.completions", + "name": "runTools", + "oldBase": "beta.chat.completions" + }, + { + "base": "files", + "name": "delete", + "oldName": "del" + }, + { + "base": "models", + "name": "delete", + "oldName": "del" + }, + { + "base": "fineTuning.checkpoints.permissions", + "name": "delete", + "params": [ + { + "type": "param", + "key": "permission_id", + "location": "path" + }, + { + "type": "params", + "maybeOverload": false + }, + { + "type": "options" + } + ], + "oldName": "del", + "oldParams": [ + { + "type": "param", + "key": "fine_tuned_model_checkpoint", + "location": "path" + }, + { + "type": "param", + "key": "permission_id", + "location": "path" + }, + { + "type": "options" + } + ] + }, + { + "base": "vectorStores", + "name": "delete", + "oldName": "del" + }, + { + "base": "vectorStores.files", + "name": "retrieve", + "params": [ + { + "type": "param", + "key": "file_id", + "location": "path" + }, + { + "type": "params", + "maybeOverload": false + }, + { + "type": "options" + } + ], + "oldParams": [ + { + "type": "param", + "key": "vector_store_id", + "location": "path" + }, + { + "type": "param", + "key": "file_id", + "location": "path" + }, + { + "type": "options" + } + ] + }, + { + "base": "vectorStores.files", + "name": "update", + "params": [ + { + "type": "param", + "key": "file_id", + "location": "path" + }, + { + "type": "params", + "maybeOverload": false + }, + { + "type": "options" + } + ], + "oldParams": [ + { + "type": "param", + "key": "vector_store_id", + "location": "path" + }, + { + "type": "param", + "key": "file_id", + "location": "path" + }, + { + "type": "params", + "maybeOverload": false + }, + { + "type": "options" + } + ] + }, + { + "base": "vectorStores.files", + "name": "delete", + "params": [ + { + "type": "param", + "key": "file_id", + "location": "path" + }, + { + "type": "params", + "maybeOverload": false + }, + { + "type": "options" + } + ], + "oldName": "del", + "oldParams": [ + { + "type": "param", + "key": "vector_store_id", + "location": "path" + }, + { + "type": "param", + "key": "file_id", + "location": "path" + }, + { + "type": "options" + } + ] + }, + { + "base": "vectorStores.files", + "name": "content", + "params": [ + { + "type": "param", + "key": "file_id", + "location": "path" + }, + { + "type": "params", + "maybeOverload": false + }, + { + "type": "options" + } + ], + "oldParams": [ + { + "type": "param", + "key": "vector_store_id", + "location": "path" + }, + { + "type": "param", + "key": "file_id", + "location": "path" + }, + { + "type": "options" + } + ] + }, + { + "base": "vectorStores.fileBatches", + "name": "retrieve", + "params": [ + { + "type": "param", + "key": "batch_id", + "location": "path" + }, + { + "type": "params", + "maybeOverload": false + }, + { + "type": "options" + } + ], + "oldParams": [ + { + "type": "param", + "key": "vector_store_id", + "location": "path" + }, + { + "type": "param", + "key": "batch_id", + "location": "path" + }, + { + "type": "options" + } + ] + }, + { + "base": "vectorStores.fileBatches", + "name": "cancel", + "params": [ + { + "type": "param", + "key": "batch_id", + "location": "path" + }, + { + "type": "params", + "maybeOverload": false + }, + { + "type": "options" + } + ], + "oldParams": [ + { + "type": "param", + "key": "vector_store_id", + "location": "path" + }, + { + "type": "param", + "key": "batch_id", + "location": "path" + }, + { + "type": "options" + } + ] + }, + { + "base": "vectorStores.fileBatches", + "name": "listFiles", + "params": [ + { + "type": "param", + "key": "batch_id", + "location": "path" + }, + { + "type": "params", + "maybeOverload": false + }, + { + "type": "options" + } + ], + "oldParams": [ + { + "type": "param", + "key": "vector_store_id", + "location": "path" + }, + { + "type": "param", + "key": "batch_id", + "location": "path" + }, + { + "type": "params", + "maybeOverload": true + }, + { + "type": "options" + } + ] + }, + { + "base": "beta.assistants", + "name": "delete", + "oldName": "del" + }, + { + "base": "beta.threads", + "name": "delete", + "oldName": "del" + }, + { + "base": "beta.threads.runs", + "name": "retrieve", + "params": [ + { + "type": "param", + "key": "run_id", + "location": "path" + }, + { + "type": "params", + "maybeOverload": false + }, + { + "type": "options" + } + ], + "oldParams": [ + { + "type": "param", + "key": "thread_id", + "location": "path" + }, + { + "type": "param", + "key": "run_id", + "location": "path" + }, + { + "type": "options" + } + ] + }, + { + "base": "beta.threads.runs", + "name": "update", + "params": [ + { + "type": "param", + "key": "run_id", + "location": "path" + }, + { + "type": "params", + "maybeOverload": false + }, + { + "type": "options" + } + ], + "oldParams": [ + { + "type": "param", + "key": "thread_id", + "location": "path" + }, + { + "type": "param", + "key": "run_id", + "location": "path" + }, + { + "type": "params", + "maybeOverload": false + }, + { + "type": "options" + } + ] + }, + { + "base": "beta.threads.runs", + "name": "cancel", + "params": [ + { + "type": "param", + "key": "run_id", + "location": "path" + }, + { + "type": "params", + "maybeOverload": false + }, + { + "type": "options" + } + ], + "oldParams": [ + { + "type": "param", + "key": "thread_id", + "location": "path" + }, + { + "type": "param", + "key": "run_id", + "location": "path" + }, + { + "type": "options" + } + ] + }, + { + "base": "beta.threads.runs", + "name": "submitToolOutputs", + "params": [ + { + "type": "param", + "key": "run_id", + "location": "path" + }, + { + "type": "params", + "maybeOverload": false + }, + { + "type": "options" + } + ], + "oldParams": [ + { + "type": "param", + "key": "thread_id", + "location": "path" + }, + { + "type": "param", + "key": "run_id", + "location": "path" + }, + { + "type": "params", + "maybeOverload": false + }, + { + "type": "options" + } + ] + }, + { + "base": "beta.threads.runs.steps", + "name": "retrieve", + "params": [ + { + "type": "param", + "key": "step_id", + "location": "path" + }, + { + "type": "params", + "maybeOverload": false + }, + { + "type": "options" + } + ], + "oldParams": [ + { + "type": "param", + "key": "thread_id", + "location": "path" + }, + { + "type": "param", + "key": "run_id", + "location": "path" + }, + { + "type": "param", + "key": "step_id", + "location": "path" + }, + { + "type": "params", + "maybeOverload": true + }, + { + "type": "options" + } + ] + }, + { + "base": "beta.threads.runs.steps", + "name": "list", + "params": [ + { + "type": "param", + "key": "run_id", + "location": "path" + }, + { + "type": "params", + "maybeOverload": false + }, + { + "type": "options" + } + ], + "oldParams": [ + { + "type": "param", + "key": "thread_id", + "location": "path" + }, + { + "type": "param", + "key": "run_id", + "location": "path" + }, + { + "type": "params", + "maybeOverload": true + }, + { + "type": "options" + } + ] + }, + { + "base": "beta.threads.messages", + "name": "retrieve", + "params": [ + { + "type": "param", + "key": "message_id", + "location": "path" + }, + { + "type": "params", + "maybeOverload": false + }, + { + "type": "options" + } + ], + "oldParams": [ + { + "type": "param", + "key": "thread_id", + "location": "path" + }, + { + "type": "param", + "key": "message_id", + "location": "path" + }, + { + "type": "options" + } + ] + }, + { + "base": "beta.threads.messages", + "name": "update", + "params": [ + { + "type": "param", + "key": "message_id", + "location": "path" + }, + { + "type": "params", + "maybeOverload": false + }, + { + "type": "options" + } + ], + "oldParams": [ + { + "type": "param", + "key": "thread_id", + "location": "path" + }, + { + "type": "param", + "key": "message_id", + "location": "path" + }, + { + "type": "params", + "maybeOverload": false + }, + { + "type": "options" + } + ] + }, + { + "base": "beta.threads.messages", + "name": "delete", + "params": [ + { + "type": "param", + "key": "message_id", + "location": "path" + }, + { + "type": "params", + "maybeOverload": false + }, + { + "type": "options" + } + ], + "oldName": "del", + "oldParams": [ + { + "type": "param", + "key": "thread_id", + "location": "path" + }, + { + "type": "param", + "key": "message_id", + "location": "path" + }, + { + "type": "options" + } + ] + }, + { + "base": "responses", + "name": "delete", + "oldName": "del" + }, + { + "base": "evals", + "name": "delete", + "oldName": "del" + }, + { + "base": "evals.runs", + "name": "retrieve", + "params": [ + { + "type": "param", + "key": "run_id", + "location": "path" + }, + { + "type": "params", + "maybeOverload": false + }, + { + "type": "options" + } + ], + "oldParams": [ + { + "type": "param", + "key": "eval_id", + "location": "path" + }, + { + "type": "param", + "key": "run_id", + "location": "path" + }, + { + "type": "options" + } + ] + }, + { + "base": "evals.runs", + "name": "delete", + "params": [ + { + "type": "param", + "key": "run_id", + "location": "path" + }, + { + "type": "params", + "maybeOverload": false + }, + { + "type": "options" + } + ], + "oldName": "del", + "oldParams": [ + { + "type": "param", + "key": "eval_id", + "location": "path" + }, + { + "type": "param", + "key": "run_id", + "location": "path" + }, + { + "type": "options" + } + ] + }, + { + "base": "evals.runs", + "name": "cancel", + "params": [ + { + "type": "param", + "key": "run_id", + "location": "path" + }, + { + "type": "params", + "maybeOverload": false + }, + { + "type": "options" + } + ], + "oldParams": [ + { + "type": "param", + "key": "eval_id", + "location": "path" + }, + { + "type": "param", + "key": "run_id", + "location": "path" + }, + { + "type": "options" + } + ] + }, + { + "base": "evals.runs.outputItems", + "name": "retrieve", + "params": [ + { + "type": "param", + "key": "output_item_id", + "location": "path" + }, + { + "type": "params", + "maybeOverload": false + }, + { + "type": "options" + } + ], + "oldParams": [ + { + "type": "param", + "key": "eval_id", + "location": "path" + }, + { + "type": "param", + "key": "run_id", + "location": "path" + }, + { + "type": "param", + "key": "output_item_id", + "location": "path" + }, + { + "type": "options" + } + ] + }, + { + "base": "evals.runs.outputItems", + "name": "list", + "params": [ + { + "type": "param", + "key": "run_id", + "location": "path" + }, + { + "type": "params", + "maybeOverload": false + }, + { + "type": "options" + } + ], + "oldParams": [ + { + "type": "param", + "key": "eval_id", + "location": "path" + }, + { + "type": "param", + "key": "run_id", + "location": "path" + }, + { + "type": "params", + "maybeOverload": true + }, + { + "type": "options" + } + ] + }, + { + "base": "containers", + "name": "delete", + "oldName": "del" + }, + { + "base": "containers.files", + "name": "retrieve", + "params": [ + { + "type": "param", + "key": "file_id", + "location": "path" + }, + { + "type": "params", + "maybeOverload": false + }, + { + "type": "options" + } + ], + "oldParams": [ + { + "type": "param", + "key": "container_id", + "location": "path" + }, + { + "type": "param", + "key": "file_id", + "location": "path" + }, + { + "type": "options" + } + ] + }, + { + "base": "containers.files", + "name": "delete", + "params": [ + { + "type": "param", + "key": "file_id", + "location": "path" + }, + { + "type": "params", + "maybeOverload": false + }, + { + "type": "options" + } + ], + "oldName": "del", + "oldParams": [ + { + "type": "param", + "key": "container_id", + "location": "path" + }, + { + "type": "param", + "key": "file_id", + "location": "path" + }, + { + "type": "options" + } + ] + }, + { + "base": "containers.files.content", + "name": "retrieve", + "params": [ + { + "type": "param", + "key": "file_id", + "location": "path" + }, + { + "type": "params", + "maybeOverload": false + }, + { + "type": "options" + } + ], + "oldParams": [ + { + "type": "param", + "key": "container_id", + "location": "path" + }, + { + "type": "param", + "key": "file_id", + "location": "path" + }, + { + "type": "options" + } + ] + } + ] +} 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..529d137af 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..98de5fa54 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", - "typescript": "5.0.4" + "bun-types": "^1.2.14", + "typescript": "5.8.3" } } diff --git a/ecosystem-tests/cli.ts b/ecosystem-tests/cli.ts index 77faddec5..9781c2b03 100644 --- a/ecosystem-tests/cli.ts +++ b/ecosystem-tests/cli.ts @@ -3,6 +3,8 @@ import execa from 'execa'; import yargs from 'yargs'; import assert from 'assert'; import path from 'path'; +import { createServer } from 'http'; +import { connect } from 'net'; const TAR_NAME = 'openai.tgz'; const PACK_FOLDER = '.pack'; @@ -21,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']); @@ -96,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') @@ -287,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..d2cfc17b3 100644 --- a/ecosystem-tests/cloudflare-worker/package.json +++ b/ecosystem-tests/cloudflare-worker/package.json @@ -11,15 +11,12 @@ "test:ci": "start-server-and-test start http://localhost:8787 test" }, "devDependencies": { - "@cloudflare/workers-types": "^4.20230419.0", + "@cloudflare/workers-types": "^4.20250525.0", "fastest-levenshtein": "^1.0.16", "jest": "^29.5.0", "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" + "typescript": "5.8.3", + "wrangler": "^3.74.0" } } diff --git a/ecosystem-tests/cloudflare-worker/src/uploadWebApiTestCases.ts b/ecosystem-tests/cloudflare-worker/src/uploadWebApiTestCases.ts index 39225fb8d..89e61e9dc 100644 --- a/ecosystem-tests/cloudflare-worker/src/uploadWebApiTestCases.ts +++ b/ecosystem-tests/cloudflare-worker/src/uploadWebApiTestCases.ts @@ -131,6 +131,7 @@ export function uploadWebApiTestCases({ }); it('toFile handles ArrayBuffer', async () => { const result = await client.files.create({ + // @ts-ignore file: await toFile(new TextEncoder().encode(fineTune).buffer, 'finetune.jsonl'), purpose: 'fine-tune', }); 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..57515d1d3 100644 --- a/ecosystem-tests/cloudflare-worker/tsconfig.check.json +++ b/ecosystem-tests/cloudflare-worker/tsconfig.check.json @@ -3,6 +3,6 @@ "include": ["src"], "exclude": ["tests", "jest.config.cjs"], "compilerOptions": { - "skipLibCheck": false + "skipLibCheck": true } } diff --git a/ecosystem-tests/cloudflare-worker/tsconfig.json b/ecosystem-tests/cloudflare-worker/tsconfig.json index cde90e627..b0a056a5d 100644 --- a/ecosystem-tests/cloudflare-worker/tsconfig.json +++ b/ecosystem-tests/cloudflare-worker/tsconfig.json @@ -12,8 +12,8 @@ // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ /* Language and Environment */ - "target": "es2021" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, - "lib": ["es2021"] /* Specify a set of bundled library declaration files that describe the target runtime environment. */, + "target": "ESNext" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, + "lib": ["ESNext"] /* Specify a set of bundled library declaration files that describe the target runtime environment. */, "jsx": "react" /* Specify what JSX code is generated. */, // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ 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..e9a7f94e1 100644 --- a/ecosystem-tests/node-ts-cjs-auto/tests/test.ts +++ b/ecosystem-tests/node-ts-cjs-auto/tests/test.ts @@ -1,6 +1,5 @@ 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'; @@ -77,7 +76,7 @@ it(`ChatCompletionStream works`, async function () { let finalMessage: OpenAI.Chat.ChatCompletionMessageParam | undefined; let finalChatCompletion: OpenAI.Chat.ChatCompletion | undefined; - const stream = client.beta.chat.completions + const stream = client.chat.completions .stream({ model: 'gpt-4', messages: [{ role: 'user', content: 'Say this is a test' }], @@ -121,7 +120,7 @@ it(`aborting ChatCompletionStream works`, async function () { let emittedError: any; let caughtError: any; const controller = new AbortController(); - const stream = client.beta.chat.completions + const stream = client.chat.completions .stream( { model: 'gpt-4', @@ -154,30 +153,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 +191,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 +207,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..e9c59f1c2 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 @@ -82,7 +81,6 @@ 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) => 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..fcffd25bc 100644 --- a/ecosystem-tests/node-ts-cjs/tests/test-node.ts +++ b/ecosystem-tests/node-ts-cjs/tests/test-node.ts @@ -1,7 +1,6 @@ -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'; @@ -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,39 @@ 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 () { +// TODO: setup proxy server +test.skip(`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..ef91fa3f0 100644 --- a/ecosystem-tests/node-ts-cjs/tsconfig.json +++ b/ecosystem-tests/node-ts-cjs/tsconfig.json @@ -9,7 +9,7 @@ /* Language and Environment */ "target": "ES2015", - "lib": ["ES2015"], + "lib": ["ES2015", "DOM.AsyncIterable"], "jsx": "react", /* Modules */ diff --git a/ecosystem-tests/node-ts-cjs/tsconfig.nodenext.json b/ecosystem-tests/node-ts-cjs/tsconfig.nodenext.json index 0efe77b4e..a5c7de8cb 100644 --- a/ecosystem-tests/node-ts-cjs/tsconfig.nodenext.json +++ b/ecosystem-tests/node-ts-cjs/tsconfig.nodenext.json @@ -9,11 +9,11 @@ /* Language and Environment */ "target": "ES2015", - "lib": ["ES2015"], + "lib": ["ES2015", "DOM.AsyncIterable"], "jsx": "react", /* 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..5e9c8f961 100644 --- a/ecosystem-tests/node-ts-esm-auto/tests/test.ts +++ b/ecosystem-tests/node-ts-esm-auto/tests/test.ts @@ -1,7 +1,5 @@ -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'; @@ -65,15 +63,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 +86,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 +124,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 +140,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..5e9c8f961 100644 --- a/ecosystem-tests/node-ts4.5-jest27/tests/test.ts +++ b/ecosystem-tests/node-ts4.5-jest28/tests/test.ts @@ -1,7 +1,5 @@ -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'; @@ -65,13 +63,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 +86,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 +124,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 +140,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/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/logprobs.ts b/examples/logprobs.ts index 8cf274a14..47dcad259 100755 --- a/examples/logprobs.ts +++ b/examples/logprobs.ts @@ -6,7 +6,7 @@ import OpenAI from 'openai'; const openai = new OpenAI(); async function main() { - const stream = await openai.beta.chat.completions + const stream = await openai.chat.completions .stream({ model: 'gpt-4', messages: [{ role: 'user', content: 'Say this is a test' }], diff --git a/examples/parsing-run-tools.ts b/examples/parsing-run-tools.ts index a3c544c3d..f94e932ad 100644 --- a/examples/parsing-run-tools.ts +++ b/examples/parsing-run-tools.ts @@ -28,7 +28,7 @@ const Condition = z.object({ const openai = new OpenAI(); async function main() { - const runner = openai.beta.chat.completions + const runner = openai.chat.completions .runTools({ model: 'gpt-4o-2024-08-06', messages: [{ role: 'user', content: `What are the last 10 orders?` }], diff --git a/examples/parsing-stream.ts b/examples/parsing-stream.ts index d9eda0a4b..08c95d91b 100644 --- a/examples/parsing-stream.ts +++ b/examples/parsing-stream.ts @@ -15,7 +15,7 @@ const MathResponse = z.object({ async function main() { const client = new OpenAI(); - const stream = client.beta.chat.completions + const stream = client.chat.completions .stream({ model: 'gpt-4o-2024-08-06', messages: [ diff --git a/examples/parsing-tools-stream.ts b/examples/parsing-tools-stream.ts index c527abd00..971e22c40 100644 --- a/examples/parsing-tools-stream.ts +++ b/examples/parsing-tools-stream.ts @@ -12,7 +12,7 @@ async function main() { const client = new OpenAI(); const refusal = process.argv.includes('refusal'); - const stream = client.beta.chat.completions + const stream = client.chat.completions .stream({ model: 'gpt-4o-2024-08-06', messages: [ diff --git a/examples/parsing-tools.ts b/examples/parsing-tools.ts index 8eaea3807..e570d8b6b 100644 --- a/examples/parsing-tools.ts +++ b/examples/parsing-tools.ts @@ -38,7 +38,7 @@ const Query = z.object({ async function main() { const client = new OpenAI(); - const completion = await client.beta.chat.completions.parse({ + const completion = await client.chat.completions.parse({ model: 'gpt-4o-2024-08-06', messages: [ { diff --git a/examples/parsing.ts b/examples/parsing.ts index d92cc2720..3e71f74f3 100644 --- a/examples/parsing.ts +++ b/examples/parsing.ts @@ -15,7 +15,7 @@ const MathResponse = z.object({ async function main() { const client = new OpenAI(); - const completion = await client.beta.chat.completions.parse({ + const completion = await client.chat.completions.parse({ model: 'gpt-4o-2024-08-06', messages: [ { role: 'system', content: 'You are a helpful math tutor.' }, diff --git a/examples/stream-to-client-browser.ts b/examples/stream-to-client-browser.ts index 4430ccc68..b2685863d 100755 --- a/examples/stream-to-client-browser.ts +++ b/examples/stream-to-client-browser.ts @@ -8,7 +8,6 @@ * remove the 'node-fetch' import, 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://localhost:3000', { diff --git a/examples/stream-to-client-express.ts b/examples/stream-to-client-express.ts index f688f42e7..22bf210c1 100755 --- a/examples/stream-to-client-express.ts +++ b/examples/stream-to-client-express.ts @@ -30,7 +30,7 @@ app.post('/', async (req: Request, res: Response) => { try { console.log('Received request:', req.body); - const stream = openai.beta.chat.completions.stream({ + const stream = openai.chat.completions.stream({ model: 'gpt-3.5-turbo', stream: true, messages: [{ role: 'user', content: req.body }], diff --git a/examples/stream-to-client-next.ts b/examples/stream-to-client-next.ts index c5c1ff317..5ea91b2d7 100755 --- a/examples/stream-to-client-next.ts +++ b/examples/stream-to-client-next.ts @@ -25,7 +25,7 @@ export const runtime = 'edge'; export default async function handler(req: NextApiRequest, res: NextApiResponse) { const openai = new OpenAI(); - const stream = openai.beta.chat.completions.stream({ + const stream = openai.chat.completions.stream({ model: 'gpt-3.5-turbo', stream: true, // @ts-ignore diff --git a/examples/stream.ts b/examples/stream.ts index 86dbde8b8..a5210e643 100644 --- a/examples/stream.ts +++ b/examples/stream.ts @@ -5,7 +5,7 @@ import OpenAI from 'openai'; const openai = new OpenAI(); async function main() { - const runner = openai.beta.chat.completions + const runner = openai.chat.completions .stream({ model: 'gpt-3.5-turbo', messages: [{ role: 'user', content: 'Say this is a test' }], diff --git a/examples/tool-call-helpers-zod.ts b/examples/tool-call-helpers-zod.ts index 700f401a6..b4e1aedcf 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(); @@ -36,24 +34,27 @@ async function getBook({ id }: GetParams) { } async function main() { - const runner = openai.beta.chat.completions + const runner = openai.chat.completions .runTools({ model: 'gpt-4-1106-preview', 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.", }), @@ -72,8 +73,10 @@ async function main() { ], }) .on('message', (msg) => console.log('msg', msg)) - .on('functionCall', (functionCall) => console.log('functionCall', functionCall)) - .on('functionCallResult', (functionCallResult) => console.log('functionCallResult', functionCallResult)) + .on('finalFunctionToolCall', (functionCall) => console.log('functionCall', functionCall)) + .on('finalFunctionToolCallResult', (functionCallResult) => + console.log('functionCallResult', functionCallResult), + ) .on('content', (diff) => process.stdout.write(diff)); const result = await runner.finalChatCompletion(); @@ -108,37 +111,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/tool-call-helpers.ts b/examples/tool-call-helpers.ts index 21b86f8fb..18baacdb4 100755 --- a/examples/tool-call-helpers.ts +++ b/examples/tool-call-helpers.ts @@ -63,7 +63,7 @@ const tools: RunnableToolFunction[] = [ ]; async function main() { - const runner = await openai.beta.chat.completions + const runner = await openai.chat.completions .runTools({ model: 'gpt-4-1106-preview', stream: true, @@ -82,8 +82,10 @@ async function main() { ], }) .on('message', (msg) => console.log('msg', msg)) - .on('functionCall', (functionCall) => console.log('functionCall', functionCall)) - .on('functionCallResult', (functionCallResult) => console.log('functionCallResult', functionCallResult)) + .on('functionToolCall', (functionCall) => console.log('functionCall', functionCall)) + .on('functionToolCallResult', (functionCallResult) => + console.log('functionCallResult', functionCallResult), + ) .on('content', (diff) => process.stdout.write(diff)); const result = await runner.finalChatCompletion(); 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/examples/ui-generation.ts b/examples/ui-generation.ts index 84636b1f0..003bb7568 100644 --- a/examples/ui-generation.ts +++ b/examples/ui-generation.ts @@ -31,7 +31,7 @@ const UISchema: z.ZodType = z.lazy(() => ); async function main() { - const completion = await openai.beta.chat.completions.parse({ + const completion = await openai.chat.completions.parse({ model: 'gpt-4o-2024-08-06', messages: [ { diff --git a/helpers.md b/helpers.md index 41b352e5e..8b25fe0a5 100644 --- a/helpers.md +++ b/helpers.md @@ -2,7 +2,7 @@ The OpenAI API supports extracting JSON from the model with the `response_format` request param, for more details on the API, see [this guide](https://platform.openai.com/docs/guides/structured-outputs). -The SDK provides a `client.beta.chat.completions.parse()` method which is a wrapper over the `client.chat.completions.create()` that +The SDK provides a `client.chat.completions.parse()` method which is a wrapper over the `client.chat.completions.create()` that provides richer integrations with TS specific types & returns a `ParsedChatCompletion` object, which is an extension of the standard `ChatCompletion` type. ## Auto-parsing response content with Zod schemas @@ -27,7 +27,7 @@ const MathResponse = z.object({ const client = new OpenAI(); -const completion = await client.beta.chat.completions.parse({ +const completion = await client.chat.completions.parse({ model: 'gpt-4o-2024-08-06', messages: [ { role: 'system', content: 'You are a helpful math tutor.' }, @@ -93,7 +93,7 @@ const Query = z.object({ }); const client = new OpenAI(); -const completion = await client.beta.chat.completions.parse({ +const completion = await client.chat.completions.parse({ model: 'gpt-4o-2024-08-06', messages: [ { @@ -122,7 +122,7 @@ main(); ### Differences from `.create()` -The `beta.chat.completions.parse()` method imposes some additional restrictions on it's usage that `chat.completions.create()` does not. +The `chat.completions.parse()` method imposes some additional restrictions on it's usage that `chat.completions.create()` does not. - If the completion completes with `finish_reason` set to `length` or `content_filter`, the `LengthFinishReasonError` / `ContentFilterFinishReasonError` errors will be raised. - Only strict function tools can be passed, e.g. `{type: 'function', function: {..., strict: true}}` @@ -304,7 +304,7 @@ See an example of streaming helpers in action in [`examples/stream.ts`](examples ### Automated function calls -We provide the `openai.beta.chat.completions.runTools({…})` +We provide the `openai.chat.completions.runTools({…})` convenience helper for using function tool calls with the `/chat/completions` endpoint which automatically call the JavaScript functions you provide and sends their results back to the `/chat/completions` endpoint, @@ -323,7 +323,7 @@ import OpenAI from 'openai'; const client = new OpenAI(); async function main() { - const runner = client.beta.chat.completions + const runner = client.chat.completions .runTools({ model: 'gpt-4o', messages: [{ role: 'user', content: 'How is the weather this week?' }], 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 64467ad45..7a4e70a43 100644 --- a/jsr.json +++ b/jsr.json @@ -1,6 +1,6 @@ { "name": "@openai/openai", - "version": "4.104.0", + "version": "5.0.0", "exports": { ".": "./index.ts", "./helpers/zod": "./helpers/zod.ts", diff --git a/package.json b/package.json index 7fd868a34..4f1f39394 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "openai", - "version": "4.104.0", + "version": "5.0.0", "description": "The official TypeScript library for the OpenAI API", "author": "OpenAI ", "types": "dist/index.d.ts", @@ -17,115 +17,66 @@ "test": "./scripts/test", "build": "./scripts/build", "prepublishOnly": "echo 'to publish, run yarn build && (cd dist; yarn publish)' && exit 1", - "format": "prettier --write --cache --cache-strategy metadata . !dist", + "format": "./scripts/format", "prepare": "if ./scripts/utils/check-is-in-git-install.sh; then ./scripts/build && ./scripts/utils/git-swap.sh; fi", "tsn": "ts-node -r tsconfig-paths/register", "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", "@types/ws": "^8.5.13", - "@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/node": "^20.17.6", + "typescript-eslint": "8.31.1", + "@typescript-eslint/eslint-plugin": "8.31.1", + "@typescript-eslint/parser": "8.31.1", + "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", + "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.4/tsc-multi-1.1.4.tgz", "tsconfig-paths": "^4.0.0", - "typescript": "^4.8.2", + "typescript": "5.8.3", "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/*" }, + "bin": { + "openai": "bin/cli" + }, "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" diff --git a/realtime.md b/realtime.md index 7e8d84a3c..df55f1a09 100644 --- a/realtime.md +++ b/realtime.md @@ -64,7 +64,7 @@ import { OpenAIRealtimeWebSocket } from 'openai/beta/realtime/websocket'; const rt = new OpenAIRealtimeWebSocket({ model: 'gpt-4o-realtime-preview-2024-12-17' }); // ... rt.socket.addEventListener('open', () => { - // ... + // ... }); ``` @@ -83,4 +83,4 @@ rt.on('error', (err) => { // likely want to continue processing events regardless of any errors throw err; }); -``` \ No newline at end of file +``` diff --git a/scripts/build b/scripts/build index 4e86f99e2..d268d6627 100755 --- a/scripts/build +++ b/scripts/build @@ -15,33 +15,30 @@ 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 if [ -e "bin/cli" ]; then - mkdir dist/bin + mkdir -p dist/bin cp -p "bin/cli" dist/bin/; fi +if [ -e "bin/migration-config.json" ]; then + mkdir -p dist/bin + cp -p "bin/migration-config.json" dist/bin/; +fi # this converts the export map paths for the dist directory # and does a few other minor things 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 +# we need to patch index.js so that `new module.exports()` works for cjs backwards +# compat. No way to get that from index.ts because it would cause compile errors # when building .mjs node scripts/utils/fix-index-exports.cjs -# with "moduleResolution": "nodenext", if ESM resolves to index.d.ts, -# it'll have TS errors on the default import. But if it resolves to -# index.d.mts the default import will work (even though both files have -# 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 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..7a7564019 100755 --- a/scripts/format +++ b/scripts/format @@ -5,4 +5,8 @@ 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 . + +echo "==> Running prettier --write" +# format things eslint didn't +./node_modules/.bin/prettier --write --cache --cache-strategy metadata . '!**/dist' '!**/*.ts' '!**/*.mts' '!**/*.cts' '!**/*.js' '!**/*.mjs' '!**/*.cjs' 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..deae575e3 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', + }; + newExports[subpath + '/*.js'] = { + default: subpath + '/*.js', + }; + newExports[subpath + '/*'] = { + import: subpath + '/*.mjs', + require: subpath + '/*.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/scripts/utils/upload-artifact.sh b/scripts/utils/upload-artifact.sh index 0e8490199..0ee2e688a 100755 --- a/scripts/utils/upload-artifact.sh +++ b/scripts/utils/upload-artifact.sh @@ -18,7 +18,7 @@ UPLOAD_RESPONSE=$(tar -cz dist | curl -v -X PUT \ if echo "$UPLOAD_RESPONSE" | grep -q "HTTP/[0-9.]* 200"; then echo -e "\033[32mUploaded build to Stainless storage.\033[0m" - echo -e "\033[32mInstallation: npm install 'https://pkg.stainless.com/s/openai-node/$SHA'\033[0m" + echo -e "\033[32mInstallation: npm install 'https://pkg.stainless.com/s/openai-typescript/$SHA'\033[0m" else echo -e "\033[31mFailed to upload artifact.\033[0m" exit 1 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 e83c7a6d3..000000000 --- a/src/_shims/index-deno.ts +++ /dev/null @@ -1,112 +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 }; - -export const init = () => {}; diff --git a/src/_shims/index.d.ts b/src/_shims/index.d.ts deleted file mode 100644 index 107cf7fd6..000000000 --- a/src/_shims/index.d.ts +++ /dev/null @@ -1,83 +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; - -export const init: () => void; diff --git a/src/_shims/index.js b/src/_shims/index.js deleted file mode 100644 index 959f2b9ce..000000000 --- a/src/_shims/index.js +++ /dev/null @@ -1,17 +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'); -exports.init = () => { - if (!shims.kind) shims.setShims(auto.getRuntime(), { auto: true }); -}; -for (const property of Object.keys(shims)) { - Object.defineProperty(exports, property, { - get() { - return shims[property]; - }, - }); -} - -exports.init(); diff --git a/src/_shims/index.mjs b/src/_shims/index.mjs deleted file mode 100644 index 26d7a716c..000000000 --- a/src/_shims/index.mjs +++ /dev/null @@ -1,11 +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'; -export const init = () => { - if (!shims.kind) shims.setShims(auto.getRuntime(), { auto: true }); -}; -export * from './registry.mjs'; - -init(); 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/_vendor/zod-to-json-schema/parsers/object.ts b/src/_vendor/zod-to-json-schema/parsers/object.ts index 25e5db116..1335c6dd0 100644 --- a/src/_vendor/zod-to-json-schema/parsers/object.ts +++ b/src/_vendor/zod-to-json-schema/parsers/object.ts @@ -46,11 +46,16 @@ export function parseObjectDef(def: ZodObjectDef, refs: Refs) { propertyPath, }); if (parsedDef === undefined) return acc; - if (refs.openaiStrictMode && propDef.isOptional() && !propDef.isNullable()) { - console.warn( + if ( + refs.openaiStrictMode && + propDef.isOptional() && + !propDef.isNullable() && + typeof propDef._def?.defaultValue === 'undefined' + ) { + throw new Error( `Zod field at \`${propertyPath.join( '/', - )}\` uses \`.optional()\` without \`.nullable()\` which is not supported by the API. See: https://platform.openai.com/docs/guides/structured-outputs?api-mode=responses#all-fields-must-be-required\nThis will become an error in a future version of the SDK.`, + )}\` uses \`.optional()\` without \`.nullable()\` which is not supported by the API. See: https://platform.openai.com/docs/guides/structured-outputs?api-mode=responses#all-fields-must-be-required`, ); } return { diff --git a/src/api-promise.ts b/src/api-promise.ts new file mode 100644 index 000000000..8c775ee69 --- /dev/null +++ b/src/api-promise.ts @@ -0,0 +1,2 @@ +/** @deprecated Import from ./core/api-promise instead */ +export * from './core/api-promise'; diff --git a/src/azure.ts b/src/azure.ts new file mode 100644 index 000000000..48ada3a28 --- /dev/null +++ b/src/azure.ts @@ -0,0 +1,198 @@ +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, NullableHeaders } 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): NullableHeaders | undefined { + return; + } + + 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', + '/images/edits', +]); + +const API_KEY_SENTINEL = ''; diff --git a/src/beta/realtime/websocket.ts b/src/beta/realtime/websocket.ts index e8900e809..2bf0b75d5 100644 --- a/src/beta/realtime/websocket.ts +++ b/src/beta/realtime/websocket.ts @@ -1,8 +1,8 @@ import { AzureOpenAI, OpenAI } from '../../index'; import { OpenAIError } from '../../error'; -import * as Core from '../../core'; 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; @@ -41,7 +41,7 @@ export class OpenAIRealtimeWebSocket extends OpenAIRealtimeEmitter { (client as any)?._options?.dangerouslyAllowBrowser ?? (client?.apiKey.startsWith('ek_') ? true : null); - if (!dangerouslyAllowBrowser && Core.isRunningInBrowser()) { + 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", ); diff --git a/src/client.ts b/src/client.ts new file mode 100644 index 000000000..9ebdf8f02 --- /dev/null +++ b/src/client.ts @@ -0,0 +1,1115 @@ +// 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, FinalizedRequestInit } from './internal/types'; +import { uuid4 } from './internal/utils/uuid'; +import { validatePositiveInteger, isAbsoluteURL, safeJSON } from './internal/utils/values'; +import { sleep } from './internal/utils/sleep'; +import { type Logger, type LogLevel, parseLogLevel } from './internal/utils/log'; +export type { Logger, LogLevel } from './internal/utils/log'; +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 './core/error'; +import * as Pagination from './core/pagination'; +import { AbstractPage, type CursorPageParams, CursorPageResponse, PageResponse } from './core/pagination'; +import * as Uploads from './core/uploads'; +import * as API from './resources/index'; +import { APIPromise } from './core/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 } from './resources/chat/chat'; +import { + ContainerCreateParams, + ContainerCreateResponse, + ContainerListParams, + ContainerListResponse, + ContainerListResponsesPage, + ContainerRetrieveResponse, + Containers, +} from './resources/containers/containers'; +import { + EvalCreateParams, + EvalCreateResponse, + EvalCustomDataSourceConfig, + EvalDeleteResponse, + EvalListParams, + EvalListResponse, + EvalListResponsesPage, + EvalRetrieveResponse, + EvalStoredCompletionsDataSourceConfig, + EvalUpdateParams, + EvalUpdateResponse, + Evals, +} from './resources/evals/evals'; +import { FineTuning } from './resources/fine-tuning/fine-tuning'; +import { Graders } from './resources/graders/graders'; +import { Responses } from './resources/responses/responses'; +import { + Upload, + UploadCompleteParams, + UploadCreateParams, + Uploads as UploadsAPIUploads, +} from './resources/uploads/uploads'; +import { + AutoFileChunkingStrategyParam, + FileChunkingStrategy, + FileChunkingStrategyParam, + OtherFileChunkingStrategyObject, + StaticFileChunkingStrategy, + StaticFileChunkingStrategyObject, + StaticFileChunkingStrategyObjectParam, + VectorStore, + VectorStoreCreateParams, + VectorStoreDeleted, + VectorStoreListParams, + VectorStoreSearchParams, + VectorStoreSearchResponse, + VectorStoreSearchResponsesPage, + VectorStoreUpdateParams, + VectorStores, + VectorStoresPage, +} from './resources/vector-stores/vector-stores'; +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'; + +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; +} + +/** + * 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; + } + + /** + * Create a new client instance re-using the same options given to the current client with optional overriding. + */ + withOptions(options: Partial): this { + return new (this.constructor as any as new (props: ClientOptions) => typeof this)({ + ...this._options, + baseURL: this.baseURL, + maxRetries: this.maxRetries, + timeout: this.timeout, + logger: this.logger, + logLevel: this.logLevel, + fetchOptions: this.fetchOptions, + apiKey: this.apiKey, + organization: this.organization, + project: this.project, + ...options, + }); + } + + protected defaultQuery(): Record | undefined { + return this._options.defaultQuery; + } + + protected validateHeaders({ values, nulls }: NullableHeaders) { + return; + } + + protected authHeaders(opts: FinalRequestOptions): NullableHeaders | undefined { + return buildHeaders([{ 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(); + } + + try { + // use undefined this binding; fetch errors if bound to something else in browser/cloudflare + return await 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( + inputOptions: FinalRequestOptions, + { retryCount = 0 }: { retryCount?: number } = {}, + ): { req: FinalizedRequestInit; url: string; timeout: number } { + const options = { ...inputOptions }; + 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: inputOptions, 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(Math.trunc(options.timeout / 1000)) } : {}), + ...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); + graders: API.Graders = new API.Graders(this); + vectorStores: API.VectorStores = new API.VectorStores(this); + beta: API.Beta = new API.Beta(this); + batches: API.Batches = new API.Batches(this); + uploads: API.Uploads = new API.Uploads(this); + responses: API.Responses = new API.Responses(this); + evals: API.Evals = new API.Evals(this); + containers: API.Containers = new API.Containers(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.Graders = Graders; +OpenAI.VectorStores = VectorStores; +OpenAI.Beta = Beta; +OpenAI.Batches = Batches; +OpenAI.Uploads = UploadsAPIUploads; +OpenAI.Responses = Responses; +OpenAI.Evals = Evals; +OpenAI.Containers = Containers; +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 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 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 ChatCompletionReasoningEffort as ChatCompletionReasoningEffort, + 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 { Graders as Graders }; + + export { + VectorStores as VectorStores, + type AutoFileChunkingStrategyParam as AutoFileChunkingStrategyParam, + type FileChunkingStrategy as FileChunkingStrategy, + type FileChunkingStrategyParam as FileChunkingStrategyParam, + type OtherFileChunkingStrategyObject as OtherFileChunkingStrategyObject, + type StaticFileChunkingStrategy as StaticFileChunkingStrategy, + type StaticFileChunkingStrategyObject as StaticFileChunkingStrategyObject, + type StaticFileChunkingStrategyObjectParam as StaticFileChunkingStrategyObjectParam, + type VectorStore as VectorStore, + type VectorStoreDeleted as VectorStoreDeleted, + type VectorStoreSearchResponse as VectorStoreSearchResponse, + type VectorStoresPage as VectorStoresPage, + type VectorStoreSearchResponsesPage as VectorStoreSearchResponsesPage, + type VectorStoreCreateParams as VectorStoreCreateParams, + type VectorStoreUpdateParams as VectorStoreUpdateParams, + type VectorStoreListParams as VectorStoreListParams, + type VectorStoreSearchParams as VectorStoreSearchParams, + }; + + 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 { Responses as Responses }; + + export { + Evals as Evals, + type EvalCustomDataSourceConfig as EvalCustomDataSourceConfig, + type EvalStoredCompletionsDataSourceConfig as EvalStoredCompletionsDataSourceConfig, + type EvalCreateResponse as EvalCreateResponse, + type EvalRetrieveResponse as EvalRetrieveResponse, + type EvalUpdateResponse as EvalUpdateResponse, + type EvalListResponse as EvalListResponse, + type EvalDeleteResponse as EvalDeleteResponse, + type EvalListResponsesPage as EvalListResponsesPage, + type EvalCreateParams as EvalCreateParams, + type EvalUpdateParams as EvalUpdateParams, + type EvalListParams as EvalListParams, + }; + + export { + Containers as Containers, + type ContainerCreateResponse as ContainerCreateResponse, + type ContainerRetrieveResponse as ContainerRetrieveResponse, + type ContainerListResponse as ContainerListResponse, + type ContainerListResponsesPage as ContainerListResponsesPage, + type ContainerCreateParams as ContainerCreateParams, + type ContainerListParams as ContainerListParams, + }; + + export type AllModels = API.AllModels; + export type ChatModel = API.ChatModel; + export type ComparisonFilter = API.ComparisonFilter; + export type CompoundFilter = API.CompoundFilter; + export type ErrorObject = API.ErrorObject; + export type FunctionDefinition = API.FunctionDefinition; + export type FunctionParameters = API.FunctionParameters; + export type Metadata = API.Metadata; + export type Reasoning = API.Reasoning; + export type ReasoningEffort = API.ReasoningEffort; + export type ResponseFormatJSONObject = API.ResponseFormatJSONObject; + export type ResponseFormatJSONSchema = API.ResponseFormatJSONSchema; + export type ResponseFormatText = API.ResponseFormatText; + export type ResponsesModel = API.ResponsesModel; +} diff --git a/src/core.ts b/src/core.ts deleted file mode 100644 index cfd4eeaa6..000000000 --- a/src/core.ts +++ /dev/null @@ -1,1330 +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, - init, -} from './_shims/index'; - -// try running side effects outside of _shims/index to workaround https://github.com/vercel/next.js/issues/76881 -init(); - -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; - -/** - * An alias to the builtin `Array` type so we can - * easily alias it in import statements if there are name clashes. - */ -type _Array = Array; - -/** - * An alias to the builtin `Record` type so we can - * easily alias it in import statements if there are name clashes. - */ -type _Record = Record; - -export type { _Array as Array, _Record as Record }; - -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 mediaType = contentType?.split(';')[0]?.trim(); - const isJSON = mediaType?.includes('application/json') || mediaType?.endsWith('+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( - inputOptions: FinalRequestOptions, - { retryCount = 0 }: { retryCount?: number } = {}, - ): { req: RequestInit; url: string; timeout: number } { - const options = { ...inputOptions }; - 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); - options.timeout = options.timeout ?? this.timeout; - const httpAgent = options.httpAgent ?? this.httpAgent ?? getDefaultAgent(url); - const minAgentTimeout = options.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 (!inputOptions.idempotencyKey) inputOptions.idempotencyKey = this.defaultIdempotencyKey(); - headers[this.idempotencyHeader] = inputOptions.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: options.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 theses headers if they were 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); - } - if ( - getHeader(defaultHeaders, 'x-stainless-timeout') === undefined && - getHeader(headers, 'x-stainless-timeout') === undefined && - options.timeout - ) { - reqHeaders['x-stainless-timeout'] = String(Math.trunc(options.timeout / 1000)); - } - - 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 as any as Record) } - ); - } - - 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); - - const fetchOptions = { - signal: controller.signal as any, - ...options, - }; - if (fetchOptions.method) { - // Custom methods like 'patch' need to be uppercased - // See https://github.com/nodejs/undici/issues/2294 - fetchOptions.method = fetchOptions.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, - 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; - - __metadata?: Record; - __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, - - __metadata: 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; - } - } -} - -const SENSITIVE_HEADERS = new Set(['authorization', 'api-key']); - -export function debug(action: string, ...args: any[]) { - if (typeof process !== 'undefined' && process?.env?.['DEBUG'] === 'true') { - const modifiedArgs = args.map((arg) => { - if (!arg) { - return arg; - } - - // Check for sensitive headers in request body 'headers' object - if (arg['headers']) { - // clone so we don't mutate - const modifiedArg = { ...arg, headers: { ...arg['headers'] } }; - - for (const header in arg['headers']) { - if (SENSITIVE_HEADERS.has(header.toLowerCase())) { - modifiedArg['headers'][header] = 'REDACTED'; - } - } - - return modifiedArg; - } - - let modifiedArg = null; - - // Check for sensitive headers in headers object - for (const header in arg) { - if (SENSITIVE_HEADERS.has(header.toLowerCase())) { - // avoid making a copy until we need to - modifiedArg ??= { ...arg }; - modifiedArg[header] = 'REDACTED'; - } - } - - return modifiedArg ?? arg; - }); - console.log(`OpenAI:DEBUG:${action}`, ...modifiedArgs); - } -} - -/** - * 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'); -}; - -/** - * Converts a Base64 encoded string to a Float32Array. - * @param base64Str - The Base64 encoded string. - * @returns An Array of numbers interpreted as Float32 values. - */ -export const toFloat32Array = (base64Str: string): Array => { - if (typeof Buffer !== 'undefined') { - // for Node.js environment - const buf = Buffer.from(base64Str, 'base64'); - return Array.from( - new Float32Array(buf.buffer, buf.byteOffset, buf.length / Float32Array.BYTES_PER_ELEMENT), - ); - } else { - // for legacy web platform APIs - const binaryStr = atob(base64Str); - const len = binaryStr.length; - const bytes = new Uint8Array(len); - for (let i = 0; i < len; i++) { - bytes[i] = binaryStr.charCodeAt(i); - } - return Array.from(new Float32Array(bytes.buffer)); - } -}; - -export function isObj(obj: unknown): obj is Record { - return obj != null && typeof obj === 'object' && !Array.isArray(obj); -} diff --git a/src/core/README.md b/src/core/README.md new file mode 100644 index 000000000..485fce861 --- /dev/null +++ b/src/core/README.md @@ -0,0 +1,3 @@ +# `core` + +This directory holds public modules implementing non-resource-specific SDK functionality. diff --git a/src/core/api-promise.ts b/src/core/api-promise.ts new file mode 100644 index 000000000..9e6c756c8 --- /dev/null +++ b/src/core/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/core/error.ts b/src/core/error.ts new file mode 100644 index 000000000..c18cc0e33 --- /dev/null +++ b/src/core/error.ts @@ -0,0 +1,154 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { castToError } from '../internal/errors'; + +export class OpenAIError extends Error {} + +export class APIError< + TStatus extends number | undefined = number | undefined, + THeaders extends Headers | undefined = Headers | undefined, + TError extends Object | undefined = Object | undefined, +> extends OpenAIError { + /** HTTP status for the response that caused the error */ + readonly status: TStatus; + /** HTTP headers for the response that caused the error */ + readonly headers: THeaders; + /** JSON body of the response that caused the error */ + readonly error: TError; + + readonly code: string | null | undefined; + readonly param: string | null | undefined; + readonly type: string | 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.requestID = headers?.get('x-request-id'); + this.error = error; + + const data = error as Record; + this.code = data?.['code']; + this.param = data?.['param']; + this.type = data?.['type']; + } + + private static makeMessage(status: number | undefined, error: any, message: string | undefined) { + const msg = + error?.message ? + typeof error.message === 'string' ? + error.message + : JSON.stringify(error.message) + : error ? JSON.stringify(error) + : message; + + if (status && msg) { + return `${status} ${msg}`; + } + if (status) { + return `${status} status code (no body)`; + } + if (msg) { + return msg; + } + return '(no status code or body)'; + } + + static generate( + status: number | undefined, + errorResponse: Object | undefined, + message: string | undefined, + headers: Headers | undefined, + ): APIError { + if (!status || !headers) { + return new APIConnectionError({ message, cause: castToError(errorResponse) }); + } + + const error = (errorResponse as Record)?.['error']; + + if (status === 400) { + return new BadRequestError(status, error, message, headers); + } + + if (status === 401) { + return new AuthenticationError(status, error, message, headers); + } + + if (status === 403) { + return new PermissionDeniedError(status, error, message, headers); + } + + if (status === 404) { + return new NotFoundError(status, error, message, headers); + } + + if (status === 409) { + return new ConflictError(status, error, message, headers); + } + + if (status === 422) { + return new UnprocessableEntityError(status, error, message, headers); + } + + if (status === 429) { + return new RateLimitError(status, error, message, headers); + } + + if (status >= 500) { + return new InternalServerError(status, error, message, headers); + } + + return new APIError(status, error, message, headers); + } +} + +export class APIUserAbortError extends APIError { + constructor({ message }: { message?: string } = {}) { + super(undefined, undefined, message || 'Request was aborted.', undefined); + } +} + +export class APIConnectionError extends APIError { + constructor({ message, cause }: { message?: string | undefined; cause?: Error | undefined }) { + super(undefined, undefined, message || 'Connection error.', undefined); + // in some environments the 'cause' property is already declared + // @ts-ignore + if (cause) this.cause = cause; + } +} + +export class APIConnectionTimeoutError extends APIConnectionError { + constructor({ message }: { message?: string } = {}) { + super({ message: message ?? 'Request timed out.' }); + } +} + +export class BadRequestError extends APIError<400, Headers> {} + +export class AuthenticationError extends APIError<401, Headers> {} + +export class PermissionDeniedError extends APIError<403, Headers> {} + +export class NotFoundError extends APIError<404, Headers> {} + +export class ConflictError extends APIError<409, Headers> {} + +export class UnprocessableEntityError extends APIError<422, Headers> {} + +export class RateLimitError extends APIError<429, Headers> {} + +export class InternalServerError extends APIError {} + +export class LengthFinishReasonError extends OpenAIError { + constructor() { + super(`Could not parse response content as the length limit was reached`); + } +} + +export class ContentFilterFinishReasonError extends OpenAIError { + constructor() { + super(`Could not parse response content as the request was rejected by the content filter`); + } +} diff --git a/src/core/pagination.ts b/src/core/pagination.ts new file mode 100644 index 000000000..6120ba4e8 --- /dev/null +++ b/src/core/pagination.ts @@ -0,0 +1,204 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +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; + + object: string; +} + +/** + * Note: no pagination actually occurs yet, this is for forwards-compatibility. + */ +export class Page extends AbstractPage implements PageResponse { + data: Array; + + object: string; + + constructor(client: OpenAI, response: Response, body: PageResponse, options: FinalRequestOptions) { + super(client, response, body, options); + + this.data = body.data || []; + this.object = body.object; + } + + getPaginatedItems(): Item[] { + return this.data ?? []; + } + + nextPageRequestOptions(): PageRequestOptions | null { + return null; + } +} + +export interface CursorPageResponse { + data: Array; + + has_more: boolean; +} + +export interface CursorPageParams { + after?: string; + + limit?: number; +} + +export class CursorPage + extends AbstractPage + implements CursorPageResponse +{ + data: Array; + + has_more: boolean; + + constructor( + client: OpenAI, + response: Response, + body: CursorPageResponse, + options: FinalRequestOptions, + ) { + super(client, response, body, options); + + this.data = body.data || []; + this.has_more = body.has_more || false; + } + + getPaginatedItems(): Item[] { + return this.data ?? []; + } + + override hasNextPage(): boolean { + if (this.has_more === false) { + return false; + } + + return super.hasNextPage(); + } + + nextPageRequestOptions(): PageRequestOptions | null { + const data = this.getPaginatedItems(); + const id = data[data.length - 1]?.id; + if (!id) { + return null; + } + + return { + ...this.options, + query: { + ...maybeObj(this.options.query), + after: id, + }, + }; + } +} diff --git a/src/core/resource.ts b/src/core/resource.ts new file mode 100644 index 000000000..8ba97f70a --- /dev/null +++ b/src/core/resource.ts @@ -0,0 +1,11 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import type { OpenAI } from '../client'; + +export class APIResource { + protected _client: OpenAI; + + constructor(client: OpenAI) { + this._client = client; + } +} diff --git a/src/core/streaming.ts b/src/core/streaming.ts new file mode 100644 index 000000000..7c76789d5 --- /dev/null +++ b/src/core/streaming.ts @@ -0,0 +1,338 @@ +import { OpenAIError } from './error'; +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 { encodeUTF8 } from '../internal/utils/bytes'; + +import { APIError } from './error'; + +type Bytes = string | ArrayBuffer | Uint8Array | null | undefined; + +export type ServerSentEvent = { + event: string | null; + data: string; + raw: string[]; +}; + +export class Stream implements AsyncIterable { + controller: AbortController; + + constructor( + private iterator: () => AsyncIterator, + controller: AbortController, + ) { + this.controller = controller; + } + + static fromSSEResponse(response: Response, controller: AbortController): Stream { + let consumed = false; + + async function* iterator(): AsyncIterator { + if (consumed) { + throw new OpenAIError('Cannot iterate over a consumed stream, use `.tee()` to split the stream.'); + } + consumed = true; + let done = false; + try { + for await (const sse of _iterSSEMessages(response, controller)) { + if (done) continue; + + if (sse.data.startsWith('[DONE]')) { + done = true; + continue; + } + + if ( + sse.event === null || + sse.event.startsWith('response.') || + sse.event.startsWith('transcript.') + ) { + let data; + + try { + data = JSON.parse(sse.data); + } catch (e) { + console.error(`Could not parse message into JSON:`, sse.data); + console.error(`From chunk:`, sse.raw); + throw e; + } + + if (data && data.error) { + throw new APIError(undefined, data.error, undefined, response.headers); + } + + yield data; + } else { + let data; + try { + data = JSON.parse(sse.data); + } catch (e) { + console.error(`Could not parse message into JSON:`, sse.data); + console.error(`From chunk:`, sse.raw); + throw e; + } + // TODO: Is this where the error should be thrown? + if (sse.event == 'error') { + throw new APIError(undefined, data.error, data.message, undefined); + } + yield { event: sse.event, data: data } as any; + } + } + done = true; + } catch (e) { + // If the user calls `stream.controller.abort()`, we should exit without throwing. + if (isAbortError(e)) return; + throw e; + } finally { + // If the user `break`s, abort the ongoing request. + if (!done) controller.abort(); + } + } + + return new Stream(iterator, controller); + } + + /** + * Generates a Stream from a newline-separated ReadableStream + * where each item is a JSON value. + */ + static fromReadableStream(readableStream: ReadableStream, controller: AbortController): Stream { + let consumed = false; + + async function* iterLines(): AsyncGenerator { + const lineDecoder = new LineDecoder(); + + const iter = ReadableStreamToAsyncIterable(readableStream); + for await (const chunk of iter) { + for (const line of lineDecoder.decode(chunk)) { + yield line; + } + } + + for (const line of lineDecoder.flush()) { + yield line; + } + } + + async function* iterator(): AsyncIterator { + if (consumed) { + throw new OpenAIError('Cannot iterate over a consumed stream, use `.tee()` to split the stream.'); + } + consumed = true; + let done = false; + try { + for await (const line of iterLines()) { + if (done) continue; + if (line) yield JSON.parse(line); + } + done = true; + } catch (e) { + // If the user calls `stream.controller.abort()`, we should exit without throwing. + if (isAbortError(e)) return; + throw e; + } finally { + // If the user `break`s, abort the ongoing request. + if (!done) controller.abort(); + } + } + + return new Stream(iterator, controller); + } + + [Symbol.asyncIterator](): AsyncIterator { + return this.iterator(); + } + + /** + * Splits the stream into two streams which can be + * independently read from at different speeds. + */ + tee(): [Stream, Stream] { + const left: Array>> = []; + const right: Array>> = []; + const iterator = this.iterator(); + + const teeIterator = (queue: Array>>): AsyncIterator => { + return { + next: () => { + if (queue.length === 0) { + const result = iterator.next(); + left.push(result); + right.push(result); + } + return queue.shift()!; + }, + }; + }; + + return [ + new Stream(() => teeIterator(left), this.controller), + new Stream(() => teeIterator(right), this.controller), + ]; + } + + /** + * Converts this stream to a newline-separated ReadableStream of + * JSON stringified values in the stream + * which can be turned back into a Stream with `Stream.fromReadableStream()`. + */ + toReadableStream(): ReadableStream { + const self = this; + let iter: AsyncIterator; + + return makeReadableStream({ + async start() { + iter = self[Symbol.asyncIterator](); + }, + async pull(ctrl: any) { + try { + const { value, done } = await iter.next(); + if (done) return ctrl.close(); + + const bytes = encodeUTF8(JSON.stringify(value) + '\n'); + + ctrl.enqueue(bytes); + } catch (err) { + ctrl.error(err); + } + }, + async cancel() { + await iter.return?.(); + }, + }); + } +} + +export async function* _iterSSEMessages( + response: Response, + controller: AbortController, +): 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 = ReadableStreamToAsyncIterable(response.body); + for await (const sseChunk of iterSSEChunks(iter)) { + for (const line of lineDecoder.decode(sseChunk)) { + const sse = sseDecoder.decode(line); + if (sse) yield sse; + } + } + + for (const line of lineDecoder.flush()) { + const sse = sseDecoder.decode(line); + if (sse) yield sse; + } +} + +/** + * Given an async iterable iterator, iterates over it and yields full + * SSE chunks, i.e. yields when a double new-line is encountered. + */ +async function* iterSSEChunks(iterator: AsyncIterableIterator): AsyncGenerator { + let data = new Uint8Array(); + + for await (const chunk of iterator) { + if (chunk == null) { + continue; + } + + const binaryChunk = + chunk instanceof ArrayBuffer ? new Uint8Array(chunk) + : typeof chunk === 'string' ? encodeUTF8(chunk) + : chunk; + + let newData = new Uint8Array(data.length + binaryChunk.length); + newData.set(data); + newData.set(binaryChunk, data.length); + data = newData; + + let patternIndex; + while ((patternIndex = findDoubleNewlineIndex(data)) !== -1) { + yield data.slice(0, patternIndex); + data = data.slice(patternIndex); + } + } + + if (data.length > 0) { + yield data; + } +} + +class SSEDecoder { + private data: string[]; + private event: string | null; + private chunks: string[]; + + constructor() { + this.event = null; + this.data = []; + this.chunks = []; + } + + decode(line: string) { + if (line.endsWith('\r')) { + line = line.substring(0, line.length - 1); + } + + if (!line) { + // empty line and we didn't previously encounter any messages + if (!this.event && !this.data.length) return null; + + const sse: ServerSentEvent = { + event: this.event, + data: this.data.join('\n'), + raw: this.chunks, + }; + + this.event = null; + this.data = []; + this.chunks = []; + + return sse; + } + + this.chunks.push(line); + + if (line.startsWith(':')) { + return null; + } + + let [fieldname, _, value] = partition(line, ':'); + + if (value.startsWith(' ')) { + value = value.substring(1); + } + + if (fieldname === 'event') { + this.event = value; + } else if (fieldname === 'data') { + this.data.push(value); + } + + return null; + } +} + +function partition(str: string, delimiter: string): [string, string, string] { + const index = str.indexOf(delimiter); + if (index !== -1) { + return [str.substring(0, index), delimiter, str.substring(index + delimiter.length)]; + } + + return [str, '', '']; +} diff --git a/src/core/uploads.ts b/src/core/uploads.ts new file mode 100644 index 000000000..2882ca6d1 --- /dev/null +++ b/src/core/uploads.ts @@ -0,0 +1,2 @@ +export { type Uploadable } from '../internal/uploads'; +export { toFile, type ToFileInput } from '../internal/to-file'; diff --git a/src/error.ts b/src/error.ts index f3dc57610..fc55f46c0 100644 --- a/src/error.ts +++ b/src/error.ts @@ -1,154 +1,2 @@ -// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -import { castToError, Headers } from './core'; - -export class OpenAIError extends Error {} - -export class APIError< - TStatus extends number | undefined = number | undefined, - THeaders extends Headers | undefined = Headers | undefined, - TError extends Object | undefined = Object | undefined, -> extends OpenAIError { - /** HTTP status for the response that caused the error */ - readonly status: TStatus; - /** HTTP headers for the response that caused the error */ - readonly headers: THeaders; - /** JSON body of the response that caused the error */ - readonly error: TError; - - readonly code: string | null | undefined; - readonly param: string | null | undefined; - readonly type: string | undefined; - - readonly request_id: 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.error = error; - - const data = error as Record; - this.code = data?.['code']; - this.param = data?.['param']; - this.type = data?.['type']; - } - - private static makeMessage(status: number | undefined, error: any, message: string | undefined) { - const msg = - error?.message ? - typeof error.message === 'string' ? - error.message - : JSON.stringify(error.message) - : error ? JSON.stringify(error) - : message; - - if (status && msg) { - return `${status} ${msg}`; - } - if (status) { - return `${status} status code (no body)`; - } - if (msg) { - return msg; - } - return '(no status code or body)'; - } - - static generate( - status: number | undefined, - errorResponse: Object | undefined, - message: string | undefined, - headers: Headers | undefined, - ): APIError { - if (!status || !headers) { - return new APIConnectionError({ message, cause: castToError(errorResponse) }); - } - - const error = (errorResponse as Record)?.['error']; - - if (status === 400) { - return new BadRequestError(status, error, message, headers); - } - - if (status === 401) { - return new AuthenticationError(status, error, message, headers); - } - - if (status === 403) { - return new PermissionDeniedError(status, error, message, headers); - } - - if (status === 404) { - return new NotFoundError(status, error, message, headers); - } - - if (status === 409) { - return new ConflictError(status, error, message, headers); - } - - if (status === 422) { - return new UnprocessableEntityError(status, error, message, headers); - } - - if (status === 429) { - return new RateLimitError(status, error, message, headers); - } - - if (status >= 500) { - return new InternalServerError(status, error, message, headers); - } - - return new APIError(status, error, message, headers); - } -} - -export class APIUserAbortError extends APIError { - constructor({ message }: { message?: string } = {}) { - super(undefined, undefined, message || 'Request was aborted.', undefined); - } -} - -export class APIConnectionError extends APIError { - constructor({ message, cause }: { message?: string | undefined; cause?: Error | undefined }) { - super(undefined, undefined, message || 'Connection error.', undefined); - // in some environments the 'cause' property is already declared - // @ts-ignore - if (cause) this.cause = cause; - } -} - -export class APIConnectionTimeoutError extends APIConnectionError { - constructor({ message }: { message?: string } = {}) { - super({ message: message ?? 'Request timed out.' }); - } -} - -export class BadRequestError extends APIError<400, Headers> {} - -export class AuthenticationError extends APIError<401, Headers> {} - -export class PermissionDeniedError extends APIError<403, Headers> {} - -export class NotFoundError extends APIError<404, Headers> {} - -export class ConflictError extends APIError<409, Headers> {} - -export class UnprocessableEntityError extends APIError<422, Headers> {} - -export class RateLimitError extends APIError<429, Headers> {} - -export class InternalServerError extends APIError {} - -export class LengthFinishReasonError extends OpenAIError { - constructor() { - super(`Could not parse response content as the length limit was reached`); - } -} - -export class ContentFilterFinishReasonError extends OpenAIError { - constructor() { - super(`Could not parse response content as the request was rejected by the content filter`); - } -} +/** @deprecated Import from ./core/error instead */ +export * from './core/error'; diff --git a/src/helpers/audio.ts b/src/helpers/audio.ts index f1a6ea371..ecb6d7481 100644 --- a/src/helpers/audio.ts +++ b/src/helpers/audio.ts @@ -1,8 +1,7 @@ -import { File } from 'formdata-node'; import { spawn } from 'node:child_process'; import { Readable } from 'node:stream'; import { platform, versions } from 'node:process'; -import { Response } from 'openai/_shims'; +import { checkFileSupport } from '../internal/uploads'; const DEFAULT_SAMPLE_RATE = 24000; const DEFAULT_CHANNELS = 1; @@ -28,6 +27,7 @@ function isResponse(stream: NodeJS.ReadableStream | Response | File): stream is } function isFile(stream: NodeJS.ReadableStream | Response | File): stream is File { + checkFileSupport(); return stream instanceof File; } @@ -37,7 +37,7 @@ async function nodejsPlayAudio(stream: NodeJS.ReadableStream | Response | File): const ffplay = spawn('ffplay', ['-autoexit', '-nodisp', '-i', 'pipe:0']); if (isResponse(stream)) { - stream.body.pipe(ffplay.stdin); + (stream.body! as any).pipe(ffplay.stdin); } else if (isFile(stream)) { Readable.from(stream.stream()).pipe(ffplay.stdin); } else { @@ -73,6 +73,7 @@ type RecordAudioOptions = { }; function nodejsRecordAudio({ signal, device, timeout }: RecordAudioOptions = {}): Promise { + checkFileSupport(); return new Promise((resolve, reject) => { const data: any[] = []; const provider = recordingProviders[platform]; diff --git a/src/helpers/zod.ts b/src/helpers/zod.ts index de4c3ba93..d12e7f3ca 100644 --- a/src/helpers/zod.ts +++ b/src/helpers/zod.ts @@ -32,7 +32,7 @@ function zodToJsonSchema(schema: ZodType, options: { name: string }): 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.ChatCompletionsPage = ChatCompletionsPage; -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.Graders = Graders; -OpenAI.VectorStores = VectorStores; -OpenAI.VectorStoresPage = VectorStoresPage; -OpenAI.VectorStoreSearchResponsesPage = VectorStoreSearchResponsesPage; -OpenAI.Beta = Beta; -OpenAI.Batches = Batches; -OpenAI.BatchesPage = BatchesPage; -OpenAI.Uploads = UploadsAPIUploads; -OpenAI.Responses = Responses; -OpenAI.Evals = Evals; -OpenAI.EvalListResponsesPage = EvalListResponsesPage; -OpenAI.Containers = Containers; -OpenAI.ContainerListResponsesPage = ContainerListResponsesPage; -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 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 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 CreateChatCompletionRequestMessage as CreateChatCompletionRequestMessage, - type ChatCompletionReasoningEffort as ChatCompletionReasoningEffort, - 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, - 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 { Graders as Graders }; - - export { - VectorStores as VectorStores, - type AutoFileChunkingStrategyParam as AutoFileChunkingStrategyParam, - type FileChunkingStrategy as FileChunkingStrategy, - type FileChunkingStrategyParam as FileChunkingStrategyParam, - type OtherFileChunkingStrategyObject as OtherFileChunkingStrategyObject, - type StaticFileChunkingStrategy as StaticFileChunkingStrategy, - type StaticFileChunkingStrategyObject as StaticFileChunkingStrategyObject, - type StaticFileChunkingStrategyObjectParam as StaticFileChunkingStrategyObjectParam, - type VectorStore as VectorStore, - type VectorStoreDeleted as VectorStoreDeleted, - type VectorStoreSearchResponse as VectorStoreSearchResponse, - VectorStoresPage as VectorStoresPage, - VectorStoreSearchResponsesPage as VectorStoreSearchResponsesPage, - type VectorStoreCreateParams as VectorStoreCreateParams, - type VectorStoreUpdateParams as VectorStoreUpdateParams, - type VectorStoreListParams as VectorStoreListParams, - type VectorStoreSearchParams as VectorStoreSearchParams, - }; - - 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 { Responses as Responses }; - - export { - Evals as Evals, - type EvalCustomDataSourceConfig as EvalCustomDataSourceConfig, - type EvalStoredCompletionsDataSourceConfig as EvalStoredCompletionsDataSourceConfig, - type EvalCreateResponse as EvalCreateResponse, - type EvalRetrieveResponse as EvalRetrieveResponse, - type EvalUpdateResponse as EvalUpdateResponse, - type EvalListResponse as EvalListResponse, - type EvalDeleteResponse as EvalDeleteResponse, - EvalListResponsesPage as EvalListResponsesPage, - type EvalCreateParams as EvalCreateParams, - type EvalUpdateParams as EvalUpdateParams, - type EvalListParams as EvalListParams, - }; - - export { - Containers as Containers, - type ContainerCreateResponse as ContainerCreateResponse, - type ContainerRetrieveResponse as ContainerRetrieveResponse, - type ContainerListResponse as ContainerListResponse, - ContainerListResponsesPage as ContainerListResponsesPage, - type ContainerCreateParams as ContainerCreateParams, - type ContainerListParams as ContainerListParams, - }; - - export type AllModels = API.AllModels; - export type ChatModel = API.ChatModel; - export type ComparisonFilter = API.ComparisonFilter; - export type CompoundFilter = API.CompoundFilter; - export type ErrorObject = API.ErrorObject; - export type FunctionDefinition = API.FunctionDefinition; - export type FunctionParameters = API.FunctionParameters; - export type Metadata = API.Metadata; - export type Reasoning = API.Reasoning; - export type ReasoningEffort = API.ReasoningEffort; - export type ResponseFormatJSONObject = API.ResponseFormatJSONObject; - export type ResponseFormatJSONSchema = API.ResponseFormatJSONSchema; - export type ResponseFormatText = API.ResponseFormatText; - export type ResponsesModel = API.ResponsesModel; -} - -// ---------------------- 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; - 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 {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.deploymentName = deployment; - } - - override buildRequest( - options: Core.FinalRequestOptions, - props: { retryCount?: number } = {}, - ): { - 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.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: 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', - '/images/edits', -]); - -const API_KEY_SENTINEL = ''; - -// ---------------------- End Azure ---------------------- - -export { toFile, fileFromPath } from './uploads'; +export { type Uploadable, toFile } from './core/uploads'; +export { APIPromise } from './core/api-promise'; +export { OpenAI, type ClientOptions } from './client'; +export { PagePromise } from './core/pagination'; export { OpenAIError, APIError, @@ -794,6 +20,6 @@ export { InternalServerError, PermissionDeniedError, UnprocessableEntityError, -} from './error'; +} from './core/error'; -export default OpenAI; +export { AzureOpenAI } from './azure'; diff --git a/src/internal/README.md b/src/internal/README.md new file mode 100644 index 000000000..3ef5a25ba --- /dev/null +++ b/src/internal/README.md @@ -0,0 +1,3 @@ +# `internal` + +The modules in this directory are not importable outside this package and will change between releases. diff --git a/src/internal/builtin-types.ts b/src/internal/builtin-types.ts new file mode 100644 index 000000000..c23d3bded --- /dev/null +++ b/src/internal/builtin-types.ts @@ -0,0 +1,93 @@ +// 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']; + +/** + * An alias to the builtin `Array` type so we can + * easily alias it in import statements if there are name clashes. + */ +type _Array = Array; + +/** + * An alias to the builtin `Record` type so we can + * easily alias it in import statements if there are name clashes. + */ +type _Record = Record; + +export type { + _Array as Array, + _BodyInit as BodyInit, + _HeadersInit as HeadersInit, + _Record as Record, + _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 947f240b3..b3bfa97cd 100644 --- a/src/internal/decoders/line.ts +++ b/src/internal/decoders/line.ts @@ -1,6 +1,6 @@ -import { OpenAIError } from '../../error'; +import { concatBytes, decodeUTF8, encodeUTF8 } from '../utils/bytes'; -export 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,12 +13,11 @@ export class LineDecoder { static NEWLINE_CHARS = new Set(['\n', '\r']); static NEWLINE_REGEXP = /\r\n|[\n\r]/g; - buffer: Uint8Array; + #buffer: Uint8Array; #carriageReturnIndex: number | null; - textDecoder: any; // TextDecoder found in browsers; not typed to avoid pulling in either "dom" or "node" types. constructor() { - this.buffer = new Uint8Array(); + this.#buffer = new Uint8Array(); this.#carriageReturnIndex = null; } @@ -29,17 +28,14 @@ export class LineDecoder { const binaryChunk = chunk instanceof ArrayBuffer ? new Uint8Array(chunk) - : typeof chunk === 'string' ? new TextEncoder().encode(chunk) + : typeof chunk === 'string' ? encodeUTF8(chunk) : chunk; - let newData = new Uint8Array(this.buffer.length + binaryChunk.length); - newData.set(this.buffer); - newData.set(binaryChunk, this.buffer.length); - this.buffer = newData; + this.#buffer = concatBytes([this.#buffer, binaryChunk]); const lines: string[] = []; let patternIndex; - while ((patternIndex = findNewlineIndex(this.buffer, this.#carriageReturnIndex)) != null) { + 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; @@ -51,8 +47,8 @@ export class LineDecoder { 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); + lines.push(decodeUTF8(this.#buffer.subarray(0, this.#carriageReturnIndex - 1))); + this.#buffer = this.#buffer.subarray(this.#carriageReturnIndex); this.#carriageReturnIndex = null; continue; } @@ -60,55 +56,18 @@ export class LineDecoder { const endIndex = this.#carriageReturnIndex !== null ? patternIndex.preceding - 1 : patternIndex.preceding; - const line = this.decodeText(this.buffer.slice(0, endIndex)); + const line = decodeUTF8(this.#buffer.subarray(0, endIndex)); lines.push(line); - this.buffer = this.buffer.slice(patternIndex.index); + this.#buffer = this.#buffer.subarray(patternIndex.index); this.#carriageReturnIndex = null; } return lines; } - decodeText(bytes: Bytes): string { - if (bytes == null) return ''; - if (typeof bytes === 'string') return bytes; - - // Node: - if (typeof Buffer !== 'undefined') { - if (bytes instanceof Buffer) { - return bytes.toString(); - } - if (bytes instanceof Uint8Array) { - return Buffer.from(bytes).toString(); - } - - throw new OpenAIError( - `Unexpected: received non-Uint8Array (${bytes.constructor.name}) stream chunk in an environment with a global "Buffer" defined, which this library assumes to be Node. Please report this error.`, - ); - } - - // Browser - if (typeof TextDecoder !== 'undefined') { - if (bytes instanceof Uint8Array || bytes instanceof ArrayBuffer) { - this.textDecoder ??= new TextDecoder('utf8'); - return this.textDecoder.decode(bytes); - } - - throw new OpenAIError( - `Unexpected: received non-Uint8Array/ArrayBuffer (${ - (bytes as any).constructor.name - }) in a web platform. Please report this error.`, - ); - } - - throw new OpenAIError( - `Unexpected: neither Buffer nor TextDecoder are available as globals. Please report this error.`, - ); - } - flush(): string[] { - if (!this.buffer.length) { + if (!this.#buffer.length) { return []; } return this.decode('\n'); diff --git a/src/internal/detect-platform.ts b/src/internal/detect-platform.ts new file mode 100644 index 000000000..e82d95c92 --- /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 ?? 'unknown'), + 'X-Stainless-Arch': normalizeArch((globalThis as any).process.arch ?? 'unknown'), + 'X-Stainless-Runtime': 'node', + 'X-Stainless-Runtime-Version': (globalThis as any).process.version ?? 'unknown', + }; + } + + 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..5cc03ce32 --- /dev/null +++ b/src/internal/headers.ts @@ -0,0 +1,97 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +type HeaderValue = string | undefined | null; +export type HeadersLike = + | Headers + | readonly 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]; + if (typeof name !== 'string') throw new TypeError('expected header name to be a string'); + 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(); + for (const headers of newHeaders) { + const seenHeaders = new Set(); + 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..5355c7728 --- /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 '../core/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 mediaType = contentType?.split(';')[0]?.trim(); + const isJSON = mediaType?.includes('application/json') || mediaType?.endsWith('+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..78daa4199 --- /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 '../core/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/to-file.ts b/src/internal/to-file.ts new file mode 100644 index 000000000..245e84933 --- /dev/null +++ b/src/internal/to-file.ts @@ -0,0 +1,154 @@ +import { BlobPart, getName, makeFile, isAsyncIterable } from './uploads'; +import type { FilePropertyBag } from './builtin-types'; +import { checkFileSupport } from './uploads'; + +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 { + checkFileSupport(); + + // 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 (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..d7928cd35 --- /dev/null +++ b/src/internal/types.ts @@ -0,0 +1,92 @@ +// 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 }; + +export type FinalizedRequestInit = RequestInit & { headers: Headers }; + +type NotAny = [unknown] extends [T] ? never : T; + +/** + * 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 = RequestInits & + /** We don't include these in the types as they'll be overridden for every request. */ + Partial>; diff --git a/src/internal/uploads.ts b/src/internal/uploads.ts new file mode 100644 index 000000000..b21555747 --- /dev/null +++ b/src/internal/uploads.ts @@ -0,0 +1,187 @@ +import { type RequestOptions } from './request-options'; +import type { FilePropertyBag, Fetch } from './builtin-types'; +import type { OpenAI } from '../client'; +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; +} + +export const checkFileSupport = () => { + if (typeof File === 'undefined') { + const { process } = globalThis as any; + const isOldNode = + typeof process?.versions?.node === 'string' && parseInt(process.versions.node.split('.')) < 20; + throw new Error( + '`File` is not defined as a global, which is required for file uploads.' + + (isOldNode ? + " Update to Node 20 LTS or newer, or set `globalThis.File` to `import('node:buffer').File`." + : ''), + ); + } +}; + +/** + * 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 { + checkFileSupport(); + 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) => 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..f230cfe9a --- /dev/null +++ b/src/internal/utils/base64.ts @@ -0,0 +1,64 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { OpenAIError } from '../../core/error'; +import { encodeUTF8 } from './bytes'; + +export const toBase64 = (data: string | Uint8Array | null | undefined): string => { + if (!data) return ''; + + if (typeof (globalThis as any).Buffer !== 'undefined') { + return (globalThis as any).Buffer.from(data).toString('base64'); + } + + if (typeof data === 'string') { + data = encodeUTF8(data); + } + + 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') { + const buf = (globalThis as any).Buffer.from(str, 'base64'); + return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength); + } + + if (typeof atob !== 'undefined') { + const bstr = atob(str); + const buf = new Uint8Array(bstr.length); + for (let i = 0; i < bstr.length; i++) { + buf[i] = bstr.charCodeAt(i); + } + return buf; + } + + throw new OpenAIError('Cannot decode base64 string; Expected `Buffer` or `atob` to be defined'); +}; + +/** + * Converts a Base64 encoded string to a Float32Array. + * @param base64Str - The Base64 encoded string. + * @returns An Array of numbers interpreted as Float32 values. + */ +export const toFloat32Array = (base64Str: string): Array => { + if (typeof Buffer !== 'undefined') { + // for Node.js environment + const buf = Buffer.from(base64Str, 'base64'); + return Array.from( + new Float32Array(buf.buffer, buf.byteOffset, buf.length / Float32Array.BYTES_PER_ELEMENT), + ); + } else { + // for legacy web platform APIs + const binaryStr = atob(base64Str); + const len = binaryStr.length; + const bytes = new Uint8Array(len); + for (let i = 0; i < len; i++) { + bytes[i] = binaryStr.charCodeAt(i); + } + return Array.from(new Float32Array(bytes.buffer)); + } +}; diff --git a/src/internal/utils/bytes.ts b/src/internal/utils/bytes.ts new file mode 100644 index 000000000..8da627abe --- /dev/null +++ b/src/internal/utils/bytes.ts @@ -0,0 +1,32 @@ +export function concatBytes(buffers: Uint8Array[]): Uint8Array { + let length = 0; + for (const buffer of buffers) { + length += buffer.length; + } + const output = new Uint8Array(length); + let index = 0; + for (const buffer of buffers) { + output.set(buffer, index); + index += buffer.length; + } + + return output; +} + +let encodeUTF8_: (str: string) => Uint8Array; +export function encodeUTF8(str: string) { + let encoder; + return ( + encodeUTF8_ ?? + ((encoder = new (globalThis as any).TextEncoder()), (encodeUTF8_ = encoder.encode.bind(encoder))) + )(str); +} + +let decodeUTF8_: (bytes: Uint8Array) => string; +export function decodeUTF8(bytes: Uint8Array) { + let decoder; + return ( + decodeUTF8_ ?? + ((decoder = new (globalThis as any).TextDecoder()), (decodeUTF8_ = decoder.decode.bind(decoder))) + )(bytes); +} 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..1aec41276 --- /dev/null +++ b/src/internal/utils/log.ts @@ -0,0 +1,126 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { hasOwn } from './values'; +import { type OpenAI } from '../../client'; +import { RequestOptions } from '../request-options'; + +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 levelNumbers = { + off: 0, + error: 200, + warn: 300, + info: 400, + debug: 500, +}; + +export const parseLogLevel = ( + maybeLevel: string | undefined, + sourceName: string, + client: OpenAI, +): LogLevel | undefined => { + if (!maybeLevel) { + return undefined; + } + if (hasOwn(levelNumbers, maybeLevel)) { + return maybeLevel; + } + loggerFor(client).warn( + `${sourceName} was set to ${JSON.stringify(maybeLevel)}, expected one of ${JSON.stringify( + Object.keys(levelNumbers), + )}`, + ); + return undefined; +}; + +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..0dceb10f1 --- /dev/null +++ b/src/internal/utils/path.ts @@ -0,0 +1,63 @@ +import { OpenAIError } from '../../core/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..b0e53aaf7 --- /dev/null +++ b/src/internal/utils/uuid.ts @@ -0,0 +1,17 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +/** + * https://stackoverflow.com/a/2117523 + */ +export let uuid4 = function () { + const { crypto } = globalThis as any; + if (crypto?.randomUUID) { + uuid4 = crypto.randomUUID.bind(crypto); + return crypto.randomUUID(); + } + const u8 = new Uint8Array(1); + const randomByte = crypto ? () => crypto.getRandomValues(u8)[0]! : () => (Math.random() * 0xff) & 0xff; + return '10000000-1000-4000-8000-100000000000'.replace(/[018]/g, (c) => + (+c ^ (randomByte() & (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..aee03b055 --- /dev/null +++ b/src/internal/utils/values.ts @@ -0,0 +1,102 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { OpenAIError } from '../../core/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); +}; + +export const safeJSON = (text: string) => { + try { + return JSON.parse(text); + } catch (err) { + return undefined; + } +}; diff --git a/src/lib/AbstractChatCompletionRunner.ts b/src/lib/AbstractChatCompletionRunner.ts index 406f5a431..da6e8d7fe 100644 --- a/src/lib/AbstractChatCompletionRunner.ts +++ b/src/lib/AbstractChatCompletionRunner.ts @@ -1,32 +1,30 @@ -import * as Core from '../core'; -import { type CompletionUsage } from '../resources/completions'; -import { - type ChatCompletion, - type ChatCompletionMessage, - type ChatCompletionMessageParam, - type ChatCompletionCreateParams, - type ChatCompletionTool, +import type { CompletionUsage } from '../resources/completions'; +import type { + ChatCompletion, + ChatCompletionMessage, + ChatCompletionMessageParam, + ChatCompletionCreateParams, + ChatCompletionTool, + ChatCompletionMessageToolCall, } from '../resources/chat/completions'; import { OpenAIError } from '../error'; import { type RunnableFunction, isRunnableFunctionWithParse, type BaseFunctionsArgs, - RunnableToolFunction, + type RunnableToolFunction, } from './RunnableFunction'; -import { ChatCompletionFunctionRunnerParams, ChatCompletionToolRunnerParams } from './ChatCompletionRunner'; -import { - ChatCompletionStreamingFunctionRunnerParams, - ChatCompletionStreamingToolRunnerParams, -} from './ChatCompletionStreamingRunner'; -import { isAssistantMessage, isFunctionMessage, isToolMessage } from './chatCompletionUtils'; +import type { ChatCompletionToolRunnerParams } from './ChatCompletionRunner'; +import type { ChatCompletionStreamingToolRunnerParams } from './ChatCompletionStreamingRunner'; +import { isAssistantMessage, isToolMessage } from './chatCompletionUtils'; import { BaseEvents, EventStream } from './EventStream'; -import { ParsedChatCompletion } from '../resources/beta/chat/completions'; -import OpenAI from '../index'; +import type { ParsedChatCompletion } from '../resources/chat/completions'; +import type OpenAI from '../index'; import { isAutoParsableTool, parseChatCompletion } from '../lib/parser'; +import type { 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; } @@ -60,15 +58,13 @@ export class AbstractChatCompletionRunner< if (emit) { this._emit('message', message); - if ((isFunctionMessage(message) || isToolMessage(message)) && message.content) { + if (isToolMessage(message) && message.content) { // Note, this assumes that {role: 'tool', content: …} is always the result of a call of tool of type=function. - this._emit('functionCallResult', message.content as string); - } else if (isAssistantMessage(message) && message.function_call) { - this._emit('functionCall', message.function_call); + this._emit('functionToolCallResult', message.content as string); } else if (isAssistantMessage(message) && message.tool_calls) { for (const tool_call of message.tool_calls) { if (tool_call.type === 'function') { - this._emit('functionCall', tool_call.function); + this._emit('functionToolCall', tool_call.function); } } } @@ -104,17 +100,12 @@ export class AbstractChatCompletionRunner< while (i-- > 0) { const message = this.messages[i]; if (isAssistantMessage(message)) { - const { function_call, ...rest } = message; - // TODO: support audio here const ret: Omit = { - ...rest, + ...message, content: (message as ChatCompletionMessage).content ?? null, refusal: (message as ChatCompletionMessage).refusal ?? null, }; - if (function_call) { - ret.function_call = function_call; - } return ret; } } @@ -130,12 +121,9 @@ export class AbstractChatCompletionRunner< return this.#getFinalMessage(); } - #getFinalFunctionCall(): ChatCompletionMessage.FunctionCall | undefined { + #getFinalFunctionToolCall(): ChatCompletionMessageToolCall.Function | undefined { for (let i = this.messages.length - 1; i >= 0; i--) { const message = this.messages[i]; - if (isAssistantMessage(message) && message?.function_call) { - return message.function_call; - } if (isAssistantMessage(message) && message?.tool_calls?.length) { return message.tool_calls.at(-1)?.function; } @@ -148,17 +136,14 @@ export class AbstractChatCompletionRunner< * @returns a promise that resolves with the content of the final FunctionCall, or rejects * if an error occurred or the stream ended prematurely without producing a ChatCompletionMessage. */ - async finalFunctionCall(): Promise { + async finalFunctionToolCall(): Promise { await this.done(); - return this.#getFinalFunctionCall(); + return this.#getFinalFunctionToolCall(); } - #getFinalFunctionCallResult(): string | undefined { + #getFinalFunctionToolCallResult(): string | undefined { for (let i = this.messages.length - 1; i >= 0; i--) { const message = this.messages[i]; - if (isFunctionMessage(message) && message.content != null) { - return message.content; - } if ( isToolMessage(message) && message.content != null && @@ -176,9 +161,9 @@ export class AbstractChatCompletionRunner< return; } - async finalFunctionCallResult(): Promise { + async finalFunctionToolCallResult(): Promise { await this.done(); - return this.#getFinalFunctionCallResult(); + return this.#getFinalFunctionToolCallResult(); } #calculateTotalUsage(): CompletionUsage { @@ -216,11 +201,11 @@ export class AbstractChatCompletionRunner< const finalContent = this.#getFinalContent(); if (finalContent) this._emit('finalContent', finalContent); - const finalFunctionCall = this.#getFinalFunctionCall(); - if (finalFunctionCall) this._emit('finalFunctionCall', finalFunctionCall); + const finalFunctionCall = this.#getFinalFunctionToolCall(); + if (finalFunctionCall) this._emit('finalFunctionToolCall', finalFunctionCall); - const finalFunctionCallResult = this.#getFinalFunctionCallResult(); - if (finalFunctionCallResult != null) this._emit('finalFunctionCallResult', finalFunctionCallResult); + const finalFunctionCallResult = this.#getFinalFunctionToolCallResult(); + if (finalFunctionCallResult != null) this._emit('finalFunctionToolCallResult', finalFunctionCallResult); if (this._chatCompletions.some((c) => c.usage)) { this._emit('totalUsage', this.#calculateTotalUsage()); @@ -238,7 +223,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 +243,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 +251,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: @@ -490,14 +390,14 @@ export class AbstractChatCompletionRunner< } export interface AbstractChatCompletionRunnerEvents extends BaseEvents { - functionCall: (functionCall: ChatCompletionMessage.FunctionCall) => void; + functionToolCall: (functionCall: ChatCompletionMessageToolCall.Function) => void; message: (message: ChatCompletionMessageParam) => void; chatCompletion: (completion: ChatCompletion) => void; finalContent: (contentSnapshot: string) => void; finalMessage: (message: ChatCompletionMessageParam) => void; finalChatCompletion: (completion: ChatCompletion) => void; - finalFunctionCall: (functionCall: ChatCompletionMessage.FunctionCall) => void; - functionCallResult: (content: string) => void; - finalFunctionCallResult: (content: string) => void; + finalFunctionToolCall: (functionCall: ChatCompletionMessageToolCall.Function) => void; + functionToolCallResult: (content: string) => void; + finalFunctionToolCallResult: (content: string) => void; totalUsage: (usage: CompletionUsage) => void; } diff --git a/src/lib/AssistantStream.ts b/src/lib/AssistantStream.ts index 9b6cc20c5..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) { @@ -679,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')) { @@ -688,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}`); } @@ -751,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); } @@ -760,19 +758,18 @@ 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); } } 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 35648c27b..5036d4f60 100644 --- a/src/lib/ChatCompletionStream.ts +++ b/src/lib/ChatCompletionStream.ts @@ -1,4 +1,3 @@ -import * as Core from '../core'; import { OpenAIError, APIUserAbortError, @@ -18,10 +17,10 @@ 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'; +import { ParsedChatCompletion } from '../resources/chat/completions'; import { AutoParseableResponseFormat, hasAutoParseableInput, @@ -31,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; @@ -159,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(() => @@ -369,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; @@ -395,7 +395,7 @@ export class ChatCompletionStream protected async _fromReadableStream( readableStream: ReadableStream, - options?: Core.RequestOptions, + options?: RequestOptions, ): Promise { const signal = options?.signal; if (signal) { diff --git a/src/lib/ChatCompletionStreamingRunner.ts b/src/lib/ChatCompletionStreamingRunner.ts index ba0c6496f..eb8fcc357 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/RunnableFunction.ts b/src/lib/RunnableFunction.ts index a645f5ebe..d387245cd 100644 --- a/src/lib/RunnableFunction.ts +++ b/src/lib/RunnableFunction.ts @@ -99,28 +99,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/chatCompletionUtils.ts b/src/lib/chatCompletionUtils.ts index 7e9f8a093..2bf0d5b47 100644 --- a/src/lib/chatCompletionUtils.ts +++ b/src/lib/chatCompletionUtils.ts @@ -1,6 +1,5 @@ import { type ChatCompletionAssistantMessageParam, - type ChatCompletionFunctionMessageParam, type ChatCompletionMessageParam, type ChatCompletionToolMessageParam, } from '../resources'; @@ -11,12 +10,6 @@ export const isAssistantMessage = ( return message?.role === 'assistant'; }; -export const isFunctionMessage = ( - message: ChatCompletionMessageParam | null | undefined, -): message is ChatCompletionFunctionMessageParam => { - return message?.role === 'function'; -}; - export const isToolMessage = ( message: ChatCompletionMessageParam | null | undefined, ): message is ChatCompletionToolMessageParam => { diff --git a/src/lib/parser.ts b/src/lib/parser.ts index d75d32a40..b396767fd 100644 --- a/src/lib/parser.ts +++ b/src/lib/parser.ts @@ -11,7 +11,7 @@ import { ParsedChatCompletion, ParsedChoice, ParsedFunctionToolCall, -} from '../resources/beta/chat/completions'; +} from '../resources/chat/completions'; import { ResponseFormatJSONSchema } from '../resources/shared'; import { ContentFilterFinishReasonError, LengthFinishReasonError, OpenAIError } from '../error'; import { type ResponseFormatTextJSONSchemaConfig } from '../resources/responses/responses'; diff --git a/src/lib/responses/ResponseStream.ts b/src/lib/responses/ResponseStream.ts index e8fe0cb3a..1c05c96ce 100644 --- a/src/lib/responses/ResponseStream.ts +++ b/src/lib/responses/ResponseStream.ts @@ -6,13 +6,13 @@ import { type ResponseCreateParamsStreaming, type ResponseStreamEvent, } from '../../resources/responses/responses'; -import * as Core from '../../core'; +import { RequestOptions } from '../../internal/request-options'; import { APIUserAbortError, OpenAIError } from '../../error'; import OpenAI from '../../index'; import { type BaseEvents, EventStream } from '../EventStream'; import { type ResponseFunctionCallArgumentsDeltaEvent, type ResponseTextDeltaEvent } from './EventTypes'; import { maybeParseResponse, ParseableToolsParams } from '../ResponsesParser'; -import { Stream } from 'openai/streaming'; +import { Stream } from '../../streaming'; export type ResponseStreamParams = ResponseCreateAndStreamParams | ResponseStreamByIdParams; @@ -77,7 +77,7 @@ export class ResponseStream static createResponse( client: OpenAI, params: ResponseStreamParams, - options?: Core.RequestOptions, + options?: RequestOptions, ): ResponseStream { const runner = new ResponseStream(params as ResponseCreateParamsStreaming); runner._run(() => @@ -165,7 +165,7 @@ export class ResponseStream protected async _createOrRetrieveResponse( client: OpenAI, params: ResponseStreamParams, - options?: Core.RequestOptions, + options?: RequestOptions, ): Promise> { const signal = options?.signal; if (signal) { diff --git a/src/pagination.ts b/src/pagination.ts index 7a513fc44..90bf015e1 100644 --- a/src/pagination.ts +++ b/src/pagination.ts @@ -1,111 +1,2 @@ -// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -import { AbstractPage, Response, APIClient, FinalRequestOptions, PageInfo } from './core'; - -export interface PageResponse { - data: Array; - - object: string; -} - -/** - * Note: no pagination actually occurs yet, this is for forwards-compatibility. - */ -export class Page extends AbstractPage implements PageResponse { - data: Array; - - object: string; - - constructor(client: APIClient, response: Response, body: PageResponse, options: FinalRequestOptions) { - super(client, response, body, options); - - this.data = body.data || []; - this.object = body.object; - } - - getPaginatedItems(): Item[] { - 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 { - return null; - } -} - -export interface CursorPageResponse { - data: Array; - - has_more: boolean; -} - -export interface CursorPageParams { - after?: string; - - limit?: number; -} - -export class CursorPage - extends AbstractPage - implements CursorPageResponse -{ - data: Array; - - has_more: boolean; - - constructor( - client: APIClient, - response: Response, - body: CursorPageResponse, - options: FinalRequestOptions, - ) { - super(client, response, body, options); - - this.data = body.data || []; - this.has_more = body.has_more || false; - } - - getPaginatedItems(): Item[] { - return this.data ?? []; - } - - override hasNextPage(): boolean { - if (this.has_more === false) { - return false; - } - - return super.hasNextPage(); - } - - // @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; - } - - nextPageInfo(): PageInfo | 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 } }; - } -} +/** @deprecated Import from ./core/pagination instead */ +export * from './core/pagination'; diff --git a/src/resource.ts b/src/resource.ts index 87847c879..363e3516b 100644 --- a/src/resource.ts +++ b/src/resource.ts @@ -1,11 +1,2 @@ -// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -import type { OpenAI } from './index'; - -export class APIResource { - protected _client: OpenAI; - - constructor(client: OpenAI) { - this._client = client; - } -} +/** @deprecated Import from ./core/resource instead */ +export * from './core/resource'; diff --git a/src/resources/beta/chat/index.ts b/src/resources/audio.ts similarity index 53% rename from src/resources/beta/chat/index.ts rename to src/resources/audio.ts index 23b1b8ff3..bc19b759c 100644 --- a/src/resources/beta/chat/index.ts +++ b/src/resources/audio.ts @@ -1,4 +1,3 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -export { Chat } from './chat'; -export { Completions } from './completions'; +export * from './audio/index'; diff --git a/src/resources/audio/audio.ts b/src/resources/audio/audio.ts index 071fe5929..081db7d99 100644 --- a/src/resources/audio/audio.ts +++ b/src/resources/audio/audio.ts @@ -1,6 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { APIResource } from '../../resource'; +import { APIResource } from '../../core/resource'; import * as SpeechAPI from './speech'; import { Speech, SpeechCreateParams, SpeechModel } from './speech'; import * as TranscriptionsAPI from './transcriptions'; diff --git a/src/resources/audio/speech.ts b/src/resources/audio/speech.ts index ccd37c092..41d890ccf 100644 --- a/src/resources/audio/speech.ts +++ b/src/resources/audio/speech.ts @@ -1,8 +1,9 @@ // 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 { APIResource } from '../../core/resource'; +import { APIPromise } from '../../core/api-promise'; +import { buildHeaders } from '../../internal/headers'; +import { RequestOptions } from '../../internal/request-options'; export class Speech extends APIResource { /** @@ -20,11 +21,11 @@ export class Speech extends APIResource { * console.log(content); * ``` */ - create(body: SpeechCreateParams, options?: Core.RequestOptions): Core.APIPromise { + create(body: SpeechCreateParams, options?: RequestOptions): APIPromise { return this._client.post('/audio/speech', { body, ...options, - headers: { Accept: 'application/octet-stream', ...options?.headers }, + headers: buildHeaders([{ Accept: 'application/octet-stream' }, options?.headers]), __binaryResponse: true, }); } diff --git a/src/resources/audio/transcriptions.ts b/src/resources/audio/transcriptions.ts index 9e5310874..3b9d34222 100644 --- a/src/resources/audio/transcriptions.ts +++ b/src/resources/audio/transcriptions.ts @@ -1,10 +1,13 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { APIResource } from '../../resource'; -import * as Core from '../../core'; +import { APIResource } from '../../core/resource'; import * as TranscriptionsAPI from './transcriptions'; import * as AudioAPI from './audio'; -import { Stream } from '../../streaming'; +import { APIPromise } from '../../core/api-promise'; +import { Stream } from '../../core/streaming'; +import { type Uploadable } from '../../core/uploads'; +import { RequestOptions } from '../../internal/request-options'; +import { multipartFormRequestOptions } from '../../internal/uploads'; export class Transcriptions extends APIResource { /** @@ -21,40 +24,40 @@ export class Transcriptions extends APIResource { */ create( body: TranscriptionCreateParamsNonStreaming<'json' | undefined>, - options?: Core.RequestOptions, - ): Core.APIPromise; + options?: RequestOptions, + ): APIPromise; create( body: TranscriptionCreateParamsNonStreaming<'verbose_json'>, - options?: Core.RequestOptions, - ): Core.APIPromise; + options?: RequestOptions, + ): APIPromise; create( body: TranscriptionCreateParamsNonStreaming<'srt' | 'vtt' | 'text'>, - options?: Core.RequestOptions, - ): Core.APIPromise; - create( - body: TranscriptionCreateParamsNonStreaming, - options?: Core.RequestOptions, - ): Core.APIPromise; + options?: RequestOptions, + ): APIPromise; + create(body: TranscriptionCreateParamsNonStreaming, options?: RequestOptions): APIPromise; create( body: TranscriptionCreateParamsStreaming, - options?: Core.RequestOptions, - ): Core.APIPromise>; + options?: RequestOptions, + ): APIPromise>; create( body: TranscriptionCreateParamsStreaming, - options?: Core.RequestOptions, - ): Core.APIPromise>; + options?: RequestOptions, + ): APIPromise>; create( body: TranscriptionCreateParams, - options?: Core.RequestOptions, - ): Core.APIPromise> { + options?: RequestOptions, + ): APIPromise> { return this._client.post( '/audio/transcriptions', - Core.multipartFormRequestOptions({ - body, - ...options, - stream: body.stream ?? false, - __metadata: { model: body.model }, - }), + multipartFormRequestOptions( + { + body, + ...options, + stream: body.stream ?? false, + __metadata: { model: body.model }, + }, + this._client, + ), ); } } @@ -315,7 +318,7 @@ export interface TranscriptionCreateParamsBase< * 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. The options are `gpt-4o-transcribe`, diff --git a/src/resources/audio/translations.ts b/src/resources/audio/translations.ts index 1edb71a7d..2e8c8f4a4 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 { APIResource } from '../../core/resource'; import * as AudioAPI from './audio'; import * as TranscriptionsAPI from './transcriptions'; +import { APIPromise } from '../../core/api-promise'; +import { type Uploadable } from '../../core/uploads'; +import { RequestOptions } from '../../internal/request-options'; +import { multipartFormRequestOptions } from '../../internal/uploads'; export class Translations extends APIResource { /** @@ -19,24 +22,21 @@ 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 { + options?: RequestOptions, + ): APIPromise { return this._client.post( '/audio/translations', - Core.multipartFormRequestOptions({ body, ...options, __metadata: { model: body.model } }), + multipartFormRequestOptions({ body, ...options, __metadata: { model: body.model } }, this._client), ); } } @@ -76,7 +76,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 2cf2ac566..b52a27226 100644 --- a/src/resources/batches.ts +++ b/src/resources/batches.ts @@ -1,40 +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 { APIResource } from '../core/resource'; import * as BatchesAPI from './batches'; import * as Shared from './shared'; -import { CursorPage, type CursorPageParams } from '../pagination'; +import { APIPromise } from '../core/api-promise'; +import { CursorPage, type CursorPageParams, PagePromise } from '../core/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 }); } /** @@ -42,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; @@ -252,14 +248,12 @@ export interface BatchCreateParams { 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.ts b/src/resources/beta.ts new file mode 100644 index 000000000..1542e942b --- /dev/null +++ b/src/resources/beta.ts @@ -0,0 +1,3 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export * from './beta/index'; diff --git a/src/resources/beta/assistants.ts b/src/resources/beta/assistants.ts index 95581bbc8..663ea9aff 100644 --- a/src/resources/beta/assistants.ts +++ b/src/resources/beta/assistants.ts @@ -1,14 +1,16 @@ // 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 { APIResource } from '../../core/resource'; import * as Shared from '../shared'; import * as MessagesAPI from './threads/messages'; import * as ThreadsAPI from './threads/threads'; import * as RunsAPI from './threads/runs/runs'; import * as StepsAPI from './threads/runs/steps'; -import { CursorPage, type CursorPageParams } from '../../pagination'; +import { APIPromise } from '../../core/api-promise'; +import { CursorPage, type CursorPageParams, PagePromise } from '../../core/pagination'; +import { buildHeaders } from '../../internal/headers'; +import { RequestOptions } from '../../internal/request-options'; +import { path } from '../../internal/utils/path'; import { AssistantStream } from '../../lib/AssistantStream'; export class Assistants extends APIResource { @@ -22,11 +24,11 @@ export class Assistants extends APIResource { * }); * ``` */ - 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]), }); } @@ -40,10 +42,10 @@ export class Assistants extends APIResource { * ); * ``` */ - 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]), }); } @@ -57,15 +59,11 @@ export class Assistants extends APIResource { * ); * ``` */ - 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]), }); } @@ -81,21 +79,13 @@ export class Assistants extends APIResource { * ``` */ 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]), }); } @@ -104,20 +94,19 @@ export class Assistants extends APIResource { * * @example * ```ts - * const assistantDeleted = await client.beta.assistants.del( - * 'assistant_id', - * ); + * const assistantDeleted = + * await client.beta.assistants.delete('assistant_id'); * ``` */ - 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. @@ -1534,8 +1523,6 @@ export interface AssistantListParams extends CursorPageParams { order?: 'asc' | 'desc'; } -Assistants.AssistantsPage = AssistantsPage; - export declare namespace Assistants { export { type Assistant as Assistant, @@ -1549,7 +1536,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 6282d4593..0d6b5e6f3 100644 --- a/src/resources/beta/beta.ts +++ b/src/resources/beta/beta.ts @@ -1,8 +1,7 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { APIResource } from '../../resource'; +import { APIResource } from '../../core/resource'; import * as AssistantsAPI from './assistants'; -import * as ChatAPI from './chat/chat'; import { Assistant, AssistantCreateParams, @@ -91,18 +90,15 @@ import { ThreadUpdateParams, Threads, } from './threads/threads'; -import { Chat } from './chat/chat'; export class Beta extends APIResource { realtime: RealtimeAPI.Realtime = new RealtimeAPI.Realtime(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.Assistants = Assistants; -Beta.AssistantsPage = AssistantsPage; Beta.Threads = Threads; export declare namespace Beta { @@ -159,8 +155,6 @@ export declare namespace Beta { type TranscriptionSessionUpdatedEvent as TranscriptionSessionUpdatedEvent, }; - export { Chat }; - export { Assistants as Assistants, type Assistant as Assistant, @@ -174,7 +168,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/chat.ts b/src/resources/beta/chat/chat.ts deleted file mode 100644 index 110ae46cb..000000000 --- a/src/resources/beta/chat/chat.ts +++ /dev/null @@ -1,12 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -import { APIResource } from '../../../resource'; -import * as CompletionsAPI from './completions'; - -export class Chat extends APIResource { - completions: CompletionsAPI.Completions = new CompletionsAPI.Completions(this._client); -} - -export namespace Chat { - export import Completions = CompletionsAPI.Completions; -} diff --git a/src/resources/beta/chat/completions.ts b/src/resources/beta/chat/completions.ts deleted file mode 100644 index 083b9914e..000000000 --- a/src/resources/beta/chat/completions.ts +++ /dev/null @@ -1,161 +0,0 @@ -// 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 { ChatCompletionToolRunnerParams } from '../../../lib/ChatCompletionRunner'; -import { ChatCompletionStreamingToolRunnerParams } from '../../../lib/ChatCompletionStreamingRunner'; -import { ChatCompletionStream, type ChatCompletionStreamParams } from '../../../lib/ChatCompletionStream'; -import { - ChatCompletion, - ChatCompletionCreateParamsNonStreaming, - ChatCompletionMessage, - ChatCompletionMessageToolCall, -} from '../../chat/completions'; -import { ExtractParsedContentFromParams, parseChatCompletion, validateInputTools } from '../../../lib/parser'; - -export { - ChatCompletionStreamingRunner, - type ChatCompletionStreamingFunctionRunnerParams, -} 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; -} - -export interface ParsedFunctionToolCall extends ChatCompletionMessageToolCall { - function: ParsedFunction; -} - -export interface ParsedChatCompletionMessage extends ChatCompletionMessage { - parsed: ParsedT | null; - tool_calls?: Array; -} - -export interface ParsedChoice extends ChatCompletion.Choice { - message: ParsedChatCompletionMessage; -} - -export interface ParsedChatCompletion extends ChatCompletion { - choices: Array>; -} - -export type ChatCompletionParseParams = ChatCompletionCreateParamsNonStreaming; - -export class Completions extends APIResource { - parse>( - body: Params, - options?: Core.RequestOptions, - ): Core.APIPromise> { - validateInputTools(body.tools); - - return this._client.chat.completions - .create(body, { - ...options, - headers: { - ...options?.headers, - 'X-Stainless-Helper-Method': 'beta.chat.completions.parse', - }, - }) - ._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 - * results back to the /chat/completions endpoint, looping as long as the model - * requests function calls. - * - * For more details and examples, see - * [the docs](https://github.com/openai/openai-node#automated-function-calls) - */ - runTools< - Params extends ChatCompletionToolRunnerParams, - ParsedT = ExtractParsedContentFromParams, - >(body: Params, options?: RunnerOptions): ChatCompletionRunner; - - runTools< - Params extends ChatCompletionStreamingToolRunnerParams, - ParsedT = ExtractParsedContentFromParams, - >(body: Params, options?: RunnerOptions): ChatCompletionStreamingRunner; - - runTools< - Params extends ChatCompletionToolRunnerParams | ChatCompletionStreamingToolRunnerParams, - ParsedT = ExtractParsedContentFromParams, - >( - body: Params, - options?: RunnerOptions, - ): ChatCompletionRunner | ChatCompletionStreamingRunner { - if (body.stream) { - return ChatCompletionStreamingRunner.runTools( - this._client, - body as ChatCompletionStreamingToolRunnerParams, - options, - ); - } - - return ChatCompletionRunner.runTools(this._client, body as ChatCompletionToolRunnerParams, options); - } - - /** - * Creates a chat completion stream - */ - stream>( - body: Params, - options?: Core.RequestOptions, - ): ChatCompletionStream { - return ChatCompletionStream.createChatCompletion(this._client, body, options); - } -} diff --git a/src/resources/beta/index.ts b/src/resources/beta/index.ts index b9cef17cb..a4d5a7ea6 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,10 +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, type AssistantResponseFormatOption, diff --git a/src/resources/beta/realtime.ts b/src/resources/beta/realtime.ts new file mode 100644 index 000000000..1c5df27d9 --- /dev/null +++ b/src/resources/beta/realtime.ts @@ -0,0 +1,3 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export * from './realtime/index'; diff --git a/src/resources/beta/realtime/realtime.ts b/src/resources/beta/realtime/realtime.ts index b9a1788ac..21550a29e 100644 --- a/src/resources/beta/realtime/realtime.ts +++ b/src/resources/beta/realtime/realtime.ts @@ -1,6 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { APIResource } from '../../../resource'; +import { APIResource } from '../../../core/resource'; import * as RealtimeAPI from './realtime'; import * as Shared from '../../shared'; import * as SessionsAPI from './sessions'; diff --git a/src/resources/beta/realtime/sessions.ts b/src/resources/beta/realtime/sessions.ts index d6fb1135e..7d7a27f13 100644 --- a/src/resources/beta/realtime/sessions.ts +++ b/src/resources/beta/realtime/sessions.ts @@ -1,7 +1,9 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { APIResource } from '../../../resource'; -import * as Core from '../../../core'; +import { APIResource } from '../../../core/resource'; +import { APIPromise } from '../../../core/api-promise'; +import { buildHeaders } from '../../../internal/headers'; +import { RequestOptions } from '../../../internal/request-options'; export class Sessions extends APIResource { /** @@ -19,11 +21,11 @@ export class Sessions extends APIResource { * await client.beta.realtime.sessions.create(); * ``` */ - create(body: SessionCreateParams, options?: Core.RequestOptions): Core.APIPromise { + create(body: SessionCreateParams, options?: RequestOptions): APIPromise { return this._client.post('/realtime/sessions', { body, ...options, - headers: { 'OpenAI-Beta': 'assistants=v2', ...options?.headers }, + headers: buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), }); } } diff --git a/src/resources/beta/realtime/transcription-sessions.ts b/src/resources/beta/realtime/transcription-sessions.ts index 5c14540f8..8f6dec5f7 100644 --- a/src/resources/beta/realtime/transcription-sessions.ts +++ b/src/resources/beta/realtime/transcription-sessions.ts @@ -1,7 +1,9 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { APIResource } from '../../../resource'; -import * as Core from '../../../core'; +import { APIResource } from '../../../core/resource'; +import { APIPromise } from '../../../core/api-promise'; +import { buildHeaders } from '../../../internal/headers'; +import { RequestOptions } from '../../../internal/request-options'; export class TranscriptionSessions extends APIResource { /** @@ -19,14 +21,11 @@ export class TranscriptionSessions extends APIResource { * await client.beta.realtime.transcriptionSessions.create(); * ``` */ - create( - body: TranscriptionSessionCreateParams, - options?: Core.RequestOptions, - ): Core.APIPromise { + create(body: TranscriptionSessionCreateParams, options?: RequestOptions): APIPromise { return this._client.post('/realtime/transcription_sessions', { body, ...options, - headers: { 'OpenAI-Beta': 'assistants=v2', ...options?.headers }, + headers: buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), }); } } diff --git a/src/resources/beta/threads.ts b/src/resources/beta/threads.ts new file mode 100644 index 000000000..705f67016 --- /dev/null +++ b/src/resources/beta/threads.ts @@ -0,0 +1,3 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export * from './threads/index'; 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 43779d427..b487d3988 100644 --- a/src/resources/beta/threads/messages.ts +++ b/src/resources/beta/threads/messages.ts @@ -1,11 +1,13 @@ // 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 { APIResource } from '../../../core/resource'; import * as Shared from '../../shared'; import * as AssistantsAPI from '../assistants'; -import { CursorPage, type CursorPageParams } from '../../../pagination'; +import { APIPromise } from '../../../core/api-promise'; +import { CursorPage, type CursorPageParams, PagePromise } from '../../../core/pagination'; +import { buildHeaders } from '../../../internal/headers'; +import { RequestOptions } from '../../../internal/request-options'; +import { path } from '../../../internal/utils/path'; /** * @deprecated The Assistants API is deprecated in favor of the Responses API @@ -16,15 +18,11 @@ export class Messages extends APIResource { * * @deprecated The Assistants API is deprecated in favor of the Responses API */ - 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]), }); } @@ -33,10 +31,11 @@ export class Messages extends APIResource { * * @deprecated The Assistants API is deprecated in favor of the Responses API */ - 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]), }); } @@ -45,16 +44,12 @@ export class Messages extends APIResource { * * @deprecated The Assistants API is deprecated in favor of the Responses API */ - 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]), }); } @@ -64,23 +59,14 @@ export class Messages extends APIResource { * @deprecated The Assistants API is deprecated in favor of the Responses API */ 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]), }); } @@ -89,15 +75,20 @@ export class Messages extends APIResource { * * @deprecated The Assistants API is deprecated in favor of the Responses API */ - 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 @@ -708,11 +699,24 @@ 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, and - * querying for objects via API or the dashboard. + * Path param: The ID of the thread to which this message belongs. + */ + 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. @@ -741,7 +745,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 { @@ -773,9 +782,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.ts b/src/resources/beta/threads/runs.ts new file mode 100644 index 000000000..a3cc2bc7f --- /dev/null +++ b/src/resources/beta/threads/runs.ts @@ -0,0 +1,3 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export * from './runs/index'; 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 fd5d82457..506c6897a 100644 --- a/src/resources/beta/threads/runs/runs.ts +++ b/src/resources/beta/threads/runs/runs.ts @@ -1,12 +1,6 @@ // 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 { APIResource } from '../../../../core/resource'; import * as RunsAPI from './runs'; import * as Shared from '../../../shared'; import * as AssistantsAPI from '../../assistants'; @@ -37,8 +31,15 @@ import { ToolCallDeltaObject, ToolCallsStepDetails, } from './steps'; -import { CursorPage, type CursorPageParams } from '../../../../pagination'; -import { Stream } from '../../../../streaming'; +import { APIPromise } from '../../../../core/api-promise'; +import { CursorPage, type CursorPageParams, PagePromise } from '../../../../core/pagination'; +import { Stream } from '../../../../core/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'; /** * @deprecated The Assistants API is deprecated in favor of the Responses API @@ -51,32 +52,28 @@ export class Runs extends APIResource { * * @deprecated The Assistants API is deprecated in favor of the Responses API */ + 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>; } @@ -86,10 +83,11 @@ export class Runs extends APIResource { * * @deprecated The Assistants API is deprecated in favor of the Responses API */ - 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]), }); } @@ -98,16 +96,12 @@ export class Runs extends APIResource { * * @deprecated The Assistants API is deprecated in favor of the Responses API */ - 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]), }); } @@ -117,23 +111,14 @@ export class Runs extends APIResource { * @deprecated The Assistants API is deprecated in favor of the Responses API */ 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]), }); } @@ -142,10 +127,11 @@ export class Runs extends APIResource { * * @deprecated The Assistants API is deprecated in favor of the Responses API */ - 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]), }); } @@ -157,10 +143,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); } /** @@ -171,7 +157,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); } @@ -182,18 +168,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(); @@ -233,7 +221,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); } @@ -246,34 +234,31 @@ export class Runs extends APIResource { * @deprecated The Assistants API is deprecated in favor of the Responses API */ 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>; } @@ -283,13 +268,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); } /** @@ -298,22 +282,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 @@ -926,11 +903,25 @@ 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, and - * querying for objects via API or the dashboard. + * 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. @@ -954,629 +945,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; - +export interface RunCancelParams { /** - * 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. + * The ID of the thread to which this run belongs. */ - 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; - - /** - * 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?: RunStreamParams.TruncationStrategy | null; + thread_id: string; } -export namespace RunStreamParams { - export interface AdditionalMessage { - /** - * The text contents of the message. - */ - content: string | Array; +export type RunCreateAndPollParams = ThreadsAPI.ThreadCreateAndRunParamsNonStreaming; - /** - * 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; +export type RunCreateAndStreamParams = RunCreateParamsBaseStream; - /** - * 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 type RunStreamParams = RunCreateParamsBaseStream; export type RunSubmitToolOutputsParams = | RunSubmitToolOutputsParamsNonStreaming @@ -1584,14 +964,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; } @@ -1616,79 +1003,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, @@ -1721,7 +1066,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 0907f69c4..bbbafb543 100644 --- a/src/resources/beta/threads/runs/steps.ts +++ b/src/resources/beta/threads/runs/steps.ts @@ -1,11 +1,13 @@ // 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 { APIResource } from '../../../../core/resource'; import * as StepsAPI from './steps'; import * as Shared from '../../../shared'; -import { CursorPage, type CursorPageParams } from '../../../../pagination'; +import { APIPromise } from '../../../../core/api-promise'; +import { CursorPage, type CursorPageParams, PagePromise } from '../../../../core/pagination'; +import { buildHeaders } from '../../../../internal/headers'; +import { RequestOptions } from '../../../../internal/request-options'; +import { path } from '../../../../internal/utils/path'; /** * @deprecated The Assistants API is deprecated in favor of the Responses API @@ -16,33 +18,12 @@ export class Steps extends APIResource { * * @deprecated The Assistants API is deprecated in favor of the Responses API */ - 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]), }); } @@ -51,35 +32,17 @@ export class Steps extends APIResource { * * @deprecated The Assistants API is deprecated in favor of the Responses API */ - 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. @@ -286,9 +249,10 @@ export namespace FileSearchToolCall { */ export interface RankingOptions { /** - * The ranker used for the file search. + * The ranker to use for the file search. If not specified will use the `auto` + * ranker. */ - ranker: 'default_2024_08_21'; + ranker: 'auto' | 'default_2024_08_21'; /** * The score threshold for the file search. All values must be a floating point @@ -710,9 +674,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) @@ -723,17 +698,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) @@ -742,14 +723,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, @@ -770,7 +749,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 b27729371..ea86b8fca 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 { APIResource } from '../../../core/resource'; import * as ThreadsAPI from './threads'; import * as Shared from '../../shared'; import * as AssistantsAPI from '../assistants'; @@ -29,10 +25,12 @@ import { MessageContentDelta, MessageContentPartParam, MessageCreateParams, + MessageDeleteParams, MessageDeleted, MessageDelta, MessageDeltaEvent, MessageListParams, + MessageRetrieveParams, MessageUpdateParams, Messages, MessagesPage, @@ -50,10 +48,12 @@ import { Run, RunCreateAndPollParams, RunCreateAndStreamParams, + RunCancelParams, RunCreateParams, RunCreateParamsNonStreaming, RunCreateParamsStreaming, RunListParams, + RunRetrieveParams, RunStatus, RunStreamParams, RunSubmitToolOutputsAndPollParams, @@ -65,7 +65,12 @@ import { Runs, RunsPage, } from './runs/runs'; -import { Stream } from '../../../streaming'; +import { APIPromise } from '../../../core/api-promise'; +import { Stream } from '../../../core/streaming'; +import { buildHeaders } from '../../../internal/headers'; +import { RequestOptions } from '../../../internal/request-options'; +import { AssistantStream, ThreadCreateAndRunParamsBaseStream } from '../../../lib/AssistantStream'; +import { path } from '../../../internal/utils/path'; /** * @deprecated The Assistants API is deprecated in favor of the Responses API @@ -79,19 +84,11 @@ export class Threads extends APIResource { * * @deprecated The Assistants API is deprecated in favor of the Responses API */ - 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]), }); } @@ -100,10 +97,10 @@ export class Threads extends APIResource { * * @deprecated The Assistants API is deprecated in favor of the Responses API */ - 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]), }); } @@ -112,11 +109,11 @@ export class Threads extends APIResource { * * @deprecated The Assistants API is deprecated in favor of the Responses API */ - 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]), }); } @@ -125,10 +122,10 @@ export class Threads extends APIResource { * * @deprecated The Assistants API is deprecated in favor of the Responses API */ - 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]), }); } @@ -137,26 +134,23 @@ export class Threads extends APIResource { * * @deprecated The Assistants API is deprecated in favor of the Responses API */ - 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>; } @@ -168,19 +162,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); } } @@ -1319,342 +1310,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 { @@ -1678,12 +1337,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, @@ -1724,10 +1385,12 @@ 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, }; export { AssistantStream }; diff --git a/src/resources/chat.ts b/src/resources/chat.ts new file mode 100644 index 000000000..b3dd87a90 --- /dev/null +++ b/src/resources/chat.ts @@ -0,0 +1,3 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export * from './chat/index'; diff --git a/src/resources/chat/chat.ts b/src/resources/chat/chat.ts index 9dbc636d8..5bf388470 100644 --- a/src/resources/chat/chat.ts +++ b/src/resources/chat/chat.ts @@ -1,6 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { APIResource } from '../../resource'; +import { APIResource } from '../../core/resource'; import * as Shared from '../shared'; import * as CompletionsAPI from './completions/completions'; import { @@ -40,13 +40,7 @@ import { ChatCompletionUpdateParams, ChatCompletionUserMessageParam, ChatCompletionsPage, - CompletionCreateParams, - CompletionCreateParamsNonStreaming, - CompletionCreateParamsStreaming, - CompletionListParams, - CompletionUpdateParams, Completions, - CreateChatCompletionRequestMessage, } from './completions/completions'; export class Chat extends APIResource { @@ -56,7 +50,6 @@ export class Chat extends APIResource { export type ChatModel = Shared.ChatModel; Chat.Completions = Completions; -Chat.ChatCompletionsPage = ChatCompletionsPage; export declare namespace Chat { export { type ChatModel as ChatModel }; @@ -92,18 +85,12 @@ export declare namespace Chat { type ChatCompletionToolChoiceOption as ChatCompletionToolChoiceOption, type ChatCompletionToolMessageParam as ChatCompletionToolMessageParam, type ChatCompletionUserMessageParam as ChatCompletionUserMessageParam, - type CreateChatCompletionRequestMessage as CreateChatCompletionRequestMessage, type ChatCompletionReasoningEffort as ChatCompletionReasoningEffort, - ChatCompletionsPage as ChatCompletionsPage, + 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 CompletionUpdateParams as CompletionUpdateParams, type ChatCompletionListParams as ChatCompletionListParams, - type CompletionListParams as CompletionListParams, }; } diff --git a/src/resources/chat/completions.ts b/src/resources/chat/completions.ts index 55b151e8b..fe7033a94 100644 --- a/src/resources/chat/completions.ts +++ b/src/resources/chat/completions.ts @@ -1 +1,3 @@ -export * from './completions/completions'; +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export * from './completions/index'; diff --git a/src/resources/chat/completions/completions.ts b/src/resources/chat/completions/completions.ts index 06bb0b495..82bb2e27c 100644 --- a/src/resources/chat/completions/completions.ts +++ b/src/resources/chat/completions/completions.ts @@ -1,16 +1,24 @@ // 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 { APIResource } from '../../../core/resource'; import * as CompletionsCompletionsAPI from './completions'; import * as CompletionsAPI from '../../completions'; import * as Shared from '../../shared'; import * as MessagesAPI from './messages'; import { MessageListParams, Messages } from './messages'; -import { CursorPage, type CursorPageParams } from '../../../pagination'; -import { Stream } from '../../../streaming'; +import { APIPromise } from '../../../core/api-promise'; +import { CursorPage, type CursorPageParams, PagePromise } from '../../../core/pagination'; +import { Stream } from '../../../core/streaming'; +import { RequestOptions } from '../../../internal/request-options'; +import { path } from '../../../internal/utils/path'; + +import { ChatCompletionRunner } from '../../../lib/ChatCompletionRunner'; +import { ChatCompletionStreamingRunner } from '../../../lib/ChatCompletionStreamingRunner'; +import { RunnerOptions } from '../../../lib/AbstractChatCompletionRunner'; +import { ChatCompletionToolRunnerParams } from '../../../lib/ChatCompletionRunner'; +import { ChatCompletionStreamingToolRunnerParams } from '../../../lib/ChatCompletionStreamingRunner'; +import { ChatCompletionStream, type ChatCompletionStreamParams } from '../../../lib/ChatCompletionStream'; +import { ExtractParsedContentFromParams, parseChatCompletion, validateInputTools } from '../../../lib/parser'; export class Completions extends APIResource { messages: MessagesAPI.Messages = new MessagesAPI.Messages(this._client); @@ -44,21 +52,18 @@ export class Completions extends APIResource { * ); * ``` */ - create( - body: ChatCompletionCreateParamsNonStreaming, - options?: Core.RequestOptions, - ): APIPromise; + create(body: ChatCompletionCreateParamsNonStreaming, options?: RequestOptions): APIPromise; create( body: ChatCompletionCreateParamsStreaming, - options?: Core.RequestOptions, + options?: RequestOptions, ): APIPromise>; create( body: ChatCompletionCreateParamsBase, - options?: Core.RequestOptions, + options?: RequestOptions, ): APIPromise | ChatCompletion>; create( body: ChatCompletionCreateParams, - options?: Core.RequestOptions, + options?: RequestOptions, ): APIPromise | APIPromise> { return this._client.post('/chat/completions', { body, ...options, stream: body.stream ?? false }) as | APIPromise @@ -75,8 +80,8 @@ export class Completions extends APIResource { * await client.chat.completions.retrieve('completion_id'); * ``` */ - retrieve(completionId: string, options?: Core.RequestOptions): Core.APIPromise { - return this._client.get(`/chat/completions/${completionId}`, options); + retrieve(completionID: string, options?: RequestOptions): APIPromise { + return this._client.get(path`/chat/completions/${completionID}`, options); } /** @@ -93,11 +98,11 @@ export class Completions extends APIResource { * ``` */ update( - completionId: string, + completionID: string, body: ChatCompletionUpdateParams, - options?: Core.RequestOptions, - ): Core.APIPromise { - return this._client.post(`/chat/completions/${completionId}`, { body, ...options }); + options?: RequestOptions, + ): APIPromise { + return this._client.post(path`/chat/completions/${completionID}`, { body, ...options }); } /** @@ -113,18 +118,10 @@ export class Completions extends APIResource { * ``` */ list( - query?: ChatCompletionListParams, - options?: Core.RequestOptions, - ): Core.PagePromise; - list(options?: Core.RequestOptions): Core.PagePromise; - list( - query: ChatCompletionListParams | Core.RequestOptions = {}, - options?: Core.RequestOptions, - ): Core.PagePromise { - if (isRequestOptions(query)) { - return this.list({}, query); - } - return this._client.getAPIList('/chat/completions', ChatCompletionsPage, { query, ...options }); + query: ChatCompletionListParams | null | undefined = {}, + options?: RequestOptions, + ): PagePromise { + return this._client.getAPIList('/chat/completions', CursorPage, { query, ...options }); } /** @@ -134,17 +131,115 @@ export class Completions extends APIResource { * @example * ```ts * const chatCompletionDeleted = - * await client.chat.completions.del('completion_id'); + * await client.chat.completions.delete('completion_id'); * ``` */ - del(completionId: string, options?: Core.RequestOptions): Core.APIPromise { - return this._client.delete(`/chat/completions/${completionId}`, options); + delete(completionID: string, options?: RequestOptions): APIPromise { + return this._client.delete(path`/chat/completions/${completionID}`, options); + } + + parse>( + body: Params, + options?: RequestOptions, + ): APIPromise> { + validateInputTools(body.tools); + + return this._client.chat.completions + .create(body, { + ...options, + headers: { + ...options?.headers, + 'X-Stainless-Helper-Method': 'chat.completions.parse', + }, + }) + ._thenUnwrap((completion) => parseChatCompletion(completion, body)); + } + + /** + * A convenience helper for using tool calls with the /chat/completions endpoint + * which automatically calls the JavaScript functions you provide and sends their + * results back to the /chat/completions endpoint, looping as long as the model + * requests function calls. + * + * For more details and examples, see + * [the docs](https://github.com/openai/openai-node#automated-function-calls) + */ + runTools< + Params extends ChatCompletionToolRunnerParams, + ParsedT = ExtractParsedContentFromParams, + >(body: Params, options?: RunnerOptions): ChatCompletionRunner; + + runTools< + Params extends ChatCompletionStreamingToolRunnerParams, + ParsedT = ExtractParsedContentFromParams, + >(body: Params, options?: RunnerOptions): ChatCompletionStreamingRunner; + + runTools< + Params extends ChatCompletionToolRunnerParams | ChatCompletionStreamingToolRunnerParams, + ParsedT = ExtractParsedContentFromParams, + >( + body: Params, + options?: RunnerOptions, + ): ChatCompletionRunner | ChatCompletionStreamingRunner { + if (body.stream) { + return ChatCompletionStreamingRunner.runTools( + this._client, + body as ChatCompletionStreamingToolRunnerParams, + options, + ); + } + + return ChatCompletionRunner.runTools(this._client, body as ChatCompletionToolRunnerParams, options); + } + + /** + * Creates a chat completion stream + */ + stream>( + body: Params, + options?: RequestOptions, + ): ChatCompletionStream { + return ChatCompletionStream.createChatCompletion(this._client, body, options); } } -export class ChatCompletionsPage extends CursorPage {} +export interface ParsedFunction extends ChatCompletionMessageToolCall.Function { + parsed_arguments?: unknown; +} + +export interface ParsedFunctionToolCall extends ChatCompletionMessageToolCall { + function: ParsedFunction; +} -export class ChatCompletionStoreMessagesPage extends CursorPage {} +export interface ParsedChatCompletionMessage extends ChatCompletionMessage { + parsed: ParsedT | null; + tool_calls?: Array; +} + +export interface ParsedChoice extends ChatCompletion.Choice { + message: ParsedChatCompletionMessage; +} + +export interface ParsedChatCompletion extends ChatCompletion { + choices: Array>; +} + +export type ChatCompletionParseParams = ChatCompletionCreateParamsNonStreaming; + +export { ChatCompletionStreamingRunner } from '../../../lib/ChatCompletionStreamingRunner'; +export { + type RunnableFunctionWithParse, + type RunnableFunctionWithoutParse, + 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 } from '../../../lib/ChatCompletionRunner'; + +export type ChatCompletionsPage = CursorPage; + +export type ChatCompletionStoreMessagesPage = CursorPage; /** * Represents a chat completion response returned by model, based on the provided @@ -1161,11 +1256,6 @@ export interface ChatCompletionUserMessageParam { name?: string; } -/** - * @deprecated ChatCompletionMessageParam should be used instead - */ -export type CreateChatCompletionRequestMessage = ChatCompletionMessageParam; - export type ChatCompletionReasoningEffort = Shared.ReasoningEffort | null; export type ChatCompletionCreateParams = @@ -1566,11 +1656,6 @@ export namespace ChatCompletionCreateParams { CompletionsCompletionsAPI.ChatCompletionCreateParamsStreaming; } -/** - * @deprecated Use ChatCompletionCreateParams instead - */ -export type CompletionCreateParams = ChatCompletionCreateParams; - export interface ChatCompletionCreateParamsNonStreaming extends ChatCompletionCreateParamsBase { /** * If set to true, the model response data will be streamed to the client as it is @@ -1585,11 +1670,6 @@ export interface ChatCompletionCreateParamsNonStreaming extends ChatCompletionCr stream?: false | null; } -/** - * @deprecated Use ChatCompletionCreateParamsNonStreaming instead - */ -export type CompletionCreateParamsNonStreaming = ChatCompletionCreateParamsNonStreaming; - export interface ChatCompletionCreateParamsStreaming extends ChatCompletionCreateParamsBase { /** * If set to true, the model response data will be streamed to the client as it is @@ -1604,11 +1684,6 @@ export interface ChatCompletionCreateParamsStreaming extends ChatCompletionCreat stream: true; } -/** - * @deprecated Use ChatCompletionCreateParamsStreaming instead - */ -export type CompletionCreateParamsStreaming = ChatCompletionCreateParamsStreaming; - export interface ChatCompletionUpdateParams { /** * Set of 16 key-value pairs that can be attached to an object. This can be useful @@ -1621,11 +1696,6 @@ export interface ChatCompletionUpdateParams { metadata: Shared.Metadata | null; } -/** - * @deprecated Use ChatCompletionUpdateParams instead - */ -export type CompletionUpdateParams = ChatCompletionUpdateParams; - export interface ChatCompletionListParams extends CursorPageParams { /** * A list of metadata keys to filter the Chat Completions by. Example: @@ -1646,12 +1716,6 @@ export interface ChatCompletionListParams extends CursorPageParams { order?: 'asc' | 'desc'; } -/** - * @deprecated Use ChatCompletionListParams instead - */ -export type CompletionListParams = ChatCompletionListParams; - -Completions.ChatCompletionsPage = ChatCompletionsPage; Completions.Messages = Messages; export declare namespace Completions { @@ -1685,19 +1749,13 @@ export declare namespace Completions { type ChatCompletionToolChoiceOption as ChatCompletionToolChoiceOption, type ChatCompletionToolMessageParam as ChatCompletionToolMessageParam, type ChatCompletionUserMessageParam as ChatCompletionUserMessageParam, - type CreateChatCompletionRequestMessage as CreateChatCompletionRequestMessage, type ChatCompletionReasoningEffort as ChatCompletionReasoningEffort, - ChatCompletionsPage as ChatCompletionsPage, + 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 CompletionUpdateParams as CompletionUpdateParams, type ChatCompletionListParams as ChatCompletionListParams, - type CompletionListParams as CompletionListParams, }; export { Messages as Messages, type MessageListParams as MessageListParams }; diff --git a/src/resources/chat/completions/index.ts b/src/resources/chat/completions/index.ts index 994d6f880..ce1897258 100644 --- a/src/resources/chat/completions/index.ts +++ b/src/resources/chat/completions/index.ts @@ -1,8 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. export { - ChatCompletionStoreMessagesPage, - ChatCompletionsPage, Completions, type ChatCompletion, type ChatCompletionAssistantMessageParam, @@ -33,16 +31,13 @@ export { type ChatCompletionToolChoiceOption, type ChatCompletionToolMessageParam, type ChatCompletionUserMessageParam, - type CreateChatCompletionRequestMessage, type ChatCompletionCreateParams, - type CompletionCreateParams, type ChatCompletionCreateParamsNonStreaming, - type CompletionCreateParamsNonStreaming, type ChatCompletionCreateParamsStreaming, - type CompletionCreateParamsStreaming, type ChatCompletionUpdateParams, - type CompletionUpdateParams, type ChatCompletionListParams, - type CompletionListParams, + type ChatCompletionStoreMessagesPage, + type ChatCompletionsPage, } from './completions'; +export * from './completions'; export { Messages, type MessageListParams } from './messages'; diff --git a/src/resources/chat/completions/messages.ts b/src/resources/chat/completions/messages.ts index ab3eb73f6..ee16e3269 100644 --- a/src/resources/chat/completions/messages.ts +++ b/src/resources/chat/completions/messages.ts @@ -1,11 +1,11 @@ // 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 { APIResource } from '../../../core/resource'; import * as CompletionsAPI from './completions'; import { ChatCompletionStoreMessagesPage } from './completions'; -import { type CursorPageParams } from '../../../pagination'; +import { CursorPage, type CursorPageParams, PagePromise } from '../../../core/pagination'; +import { RequestOptions } from '../../../internal/request-options'; +import { path } from '../../../internal/utils/path'; export class Messages extends APIResource { /** @@ -23,25 +23,13 @@ export class Messages extends APIResource { * ``` */ list( - completionId: string, - query?: MessageListParams, - options?: Core.RequestOptions, - ): Core.PagePromise; - list( - completionId: string, - options?: Core.RequestOptions, - ): Core.PagePromise; - list( - completionId: string, - query: MessageListParams | Core.RequestOptions = {}, - options?: Core.RequestOptions, - ): Core.PagePromise { - if (isRequestOptions(query)) { - return this.list(completionId, {}, query); - } + completionID: string, + query: MessageListParams | null | undefined = {}, + options?: RequestOptions, + ): PagePromise { return this._client.getAPIList( - `/chat/completions/${completionId}/messages`, - ChatCompletionStoreMessagesPage, + path`/chat/completions/${completionID}/messages`, + CursorPage, { query, ...options }, ); } @@ -59,4 +47,4 @@ export declare namespace Messages { export { type MessageListParams as MessageListParams }; } -export { ChatCompletionStoreMessagesPage }; +export { type ChatCompletionStoreMessagesPage }; diff --git a/src/resources/chat/index.ts b/src/resources/chat/index.ts index 62ca758e0..3e997dd86 100644 --- a/src/resources/chat/index.ts +++ b/src/resources/chat/index.ts @@ -2,8 +2,6 @@ export { Chat } from './chat'; export { - ChatCompletionStoreMessagesPage, - ChatCompletionsPage, Completions, type ChatCompletion, type ChatCompletionAssistantMessageParam, @@ -34,15 +32,11 @@ export { type ChatCompletionToolChoiceOption, type ChatCompletionToolMessageParam, type ChatCompletionUserMessageParam, - type CreateChatCompletionRequestMessage, type ChatCompletionCreateParams, - type CompletionCreateParams, type ChatCompletionCreateParamsNonStreaming, - type CompletionCreateParamsNonStreaming, type ChatCompletionCreateParamsStreaming, - type CompletionCreateParamsStreaming, type ChatCompletionUpdateParams, - type CompletionUpdateParams, type ChatCompletionListParams, - type CompletionListParams, + type ChatCompletionStoreMessagesPage, + type ChatCompletionsPage, } from './completions/index'; diff --git a/src/resources/completions.ts b/src/resources/completions.ts index 07cb49ed9..042e51693 100644 --- a/src/resources/completions.ts +++ b/src/resources/completions.ts @@ -1,11 +1,11 @@ // 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 { APIResource } from '../core/resource'; import * as CompletionsAPI from './completions'; import * as CompletionsCompletionsAPI from './chat/completions/completions'; -import { Stream } from '../streaming'; +import { APIPromise } from '../core/api-promise'; +import { Stream } from '../core/streaming'; +import { RequestOptions } from '../internal/request-options'; export class Completions extends APIResource { /** @@ -19,18 +19,15 @@ export class Completions extends APIResource { * }); * ``` */ - 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 diff --git a/src/resources/containers/containers.ts b/src/resources/containers/containers.ts index 66303dc61..7fd73ebc0 100644 --- a/src/resources/containers/containers.ts +++ b/src/resources/containers/containers.ts @@ -1,19 +1,23 @@ // 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 { APIResource } from '../../core/resource'; import * as FilesAPI from './files/files'; import { FileCreateParams, FileCreateResponse, + FileDeleteParams, FileListParams, FileListResponse, FileListResponsesPage, + FileRetrieveParams, FileRetrieveResponse, Files, } from './files/files'; -import { CursorPage, type CursorPageParams } from '../../pagination'; +import { APIPromise } from '../../core/api-promise'; +import { CursorPage, type CursorPageParams, PagePromise } from '../../core/pagination'; +import { buildHeaders } from '../../internal/headers'; +import { RequestOptions } from '../../internal/request-options'; +import { path } from '../../internal/utils/path'; export class Containers extends APIResource { files: FilesAPI.Files = new FilesAPI.Files(this._client); @@ -21,50 +25,39 @@ export class Containers extends APIResource { /** * Create Container */ - create( - body: ContainerCreateParams, - options?: Core.RequestOptions, - ): Core.APIPromise { + create(body: ContainerCreateParams, options?: RequestOptions): APIPromise { return this._client.post('/containers', { body, ...options }); } /** * Retrieve Container */ - retrieve(containerId: string, options?: Core.RequestOptions): Core.APIPromise { - return this._client.get(`/containers/${containerId}`, options); + retrieve(containerID: string, options?: RequestOptions): APIPromise { + return this._client.get(path`/containers/${containerID}`, options); } /** * List Containers */ list( - query?: ContainerListParams, - options?: Core.RequestOptions, - ): Core.PagePromise; - list(options?: Core.RequestOptions): Core.PagePromise; - list( - query: ContainerListParams | Core.RequestOptions = {}, - options?: Core.RequestOptions, - ): Core.PagePromise { - if (isRequestOptions(query)) { - return this.list({}, query); - } - return this._client.getAPIList('/containers', ContainerListResponsesPage, { query, ...options }); + query: ContainerListParams | null | undefined = {}, + options?: RequestOptions, + ): PagePromise { + return this._client.getAPIList('/containers', CursorPage, { query, ...options }); } /** * Delete Container */ - del(containerId: string, options?: Core.RequestOptions): Core.APIPromise { - return this._client.delete(`/containers/${containerId}`, { + delete(containerID: string, options?: RequestOptions): APIPromise { + return this._client.delete(path`/containers/${containerID}`, { ...options, - headers: { Accept: '*/*', ...options?.headers }, + headers: buildHeaders([{ Accept: '*/*' }, options?.headers]), }); } } -export class ContainerListResponsesPage extends CursorPage {} +export type ContainerListResponsesPage = CursorPage; export interface ContainerCreateResponse { /** @@ -265,16 +258,14 @@ export interface ContainerListParams extends CursorPageParams { order?: 'asc' | 'desc'; } -Containers.ContainerListResponsesPage = ContainerListResponsesPage; Containers.Files = Files; -Containers.FileListResponsesPage = FileListResponsesPage; export declare namespace Containers { export { type ContainerCreateResponse as ContainerCreateResponse, type ContainerRetrieveResponse as ContainerRetrieveResponse, type ContainerListResponse as ContainerListResponse, - ContainerListResponsesPage as ContainerListResponsesPage, + type ContainerListResponsesPage as ContainerListResponsesPage, type ContainerCreateParams as ContainerCreateParams, type ContainerListParams as ContainerListParams, }; @@ -284,8 +275,10 @@ export declare namespace Containers { type FileCreateResponse as FileCreateResponse, type FileRetrieveResponse as FileRetrieveResponse, type FileListResponse as FileListResponse, - FileListResponsesPage as FileListResponsesPage, + type FileListResponsesPage as FileListResponsesPage, type FileCreateParams as FileCreateParams, + type FileRetrieveParams as FileRetrieveParams, type FileListParams as FileListParams, + type FileDeleteParams as FileDeleteParams, }; } diff --git a/src/resources/containers/files/content.ts b/src/resources/containers/files/content.ts index e99d75459..76ceb1703 100644 --- a/src/resources/containers/files/content.ts +++ b/src/resources/containers/files/content.ts @@ -1,18 +1,29 @@ // 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 { APIResource } from '../../../core/resource'; +import { APIPromise } from '../../../core/api-promise'; +import { buildHeaders } from '../../../internal/headers'; +import { RequestOptions } from '../../../internal/request-options'; +import { path } from '../../../internal/utils/path'; export class Content extends APIResource { /** * Retrieve Container File Content */ - retrieve(containerId: string, fileId: string, options?: Core.RequestOptions): Core.APIPromise { - return this._client.get(`/containers/${containerId}/files/${fileId}/content`, { + retrieve(fileID: string, params: ContentRetrieveParams, options?: RequestOptions): APIPromise { + const { container_id } = params; + return this._client.get(path`/containers/${container_id}/files/${fileID}/content`, { ...options, - headers: { Accept: 'application/binary', ...options?.headers }, + headers: buildHeaders([{ Accept: 'application/binary' }, options?.headers]), __binaryResponse: true, }); } } + +export interface ContentRetrieveParams { + container_id: string; +} + +export declare namespace Content { + export { type ContentRetrieveParams as ContentRetrieveParams }; +} diff --git a/src/resources/containers/files/files.ts b/src/resources/containers/files/files.ts index eb4159a5c..cc98d7bf9 100644 --- a/src/resources/containers/files/files.ts +++ b/src/resources/containers/files/files.ts @@ -1,11 +1,15 @@ // 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 { APIResource } from '../../../core/resource'; import * as ContentAPI from './content'; -import { Content } from './content'; -import { CursorPage, type CursorPageParams } from '../../../pagination'; +import { Content, ContentRetrieveParams } from './content'; +import { APIPromise } from '../../../core/api-promise'; +import { CursorPage, type CursorPageParams, PagePromise } from '../../../core/pagination'; +import { type Uploadable } from '../../../core/uploads'; +import { buildHeaders } from '../../../internal/headers'; +import { RequestOptions } from '../../../internal/request-options'; +import { multipartFormRequestOptions } from '../../../internal/uploads'; +import { path } from '../../../internal/utils/path'; export class Files extends APIResource { content: ContentAPI.Content = new ContentAPI.Content(this._client); @@ -17,13 +21,13 @@ export class Files extends APIResource { * a JSON request with a file ID. */ create( - containerId: string, + containerID: string, body: FileCreateParams, - options?: Core.RequestOptions, - ): Core.APIPromise { + options?: RequestOptions, + ): APIPromise { return this._client.post( - `/containers/${containerId}/files`, - Core.multipartFormRequestOptions({ body, ...options }), + path`/containers/${containerID}/files`, + multipartFormRequestOptions({ body, ...options }, this._client), ); } @@ -31,34 +35,23 @@ export class Files extends APIResource { * Retrieve Container File */ retrieve( - containerId: string, - fileId: string, - options?: Core.RequestOptions, - ): Core.APIPromise { - return this._client.get(`/containers/${containerId}/files/${fileId}`, options); + fileID: string, + params: FileRetrieveParams, + options?: RequestOptions, + ): APIPromise { + const { container_id } = params; + return this._client.get(path`/containers/${container_id}/files/${fileID}`, options); } /** * List Container files */ list( - containerId: string, - query?: FileListParams, - options?: Core.RequestOptions, - ): Core.PagePromise; - list( - containerId: string, - options?: Core.RequestOptions, - ): Core.PagePromise; - list( - containerId: string, - query: FileListParams | Core.RequestOptions = {}, - options?: Core.RequestOptions, - ): Core.PagePromise { - if (isRequestOptions(query)) { - return this.list(containerId, {}, query); - } - return this._client.getAPIList(`/containers/${containerId}/files`, FileListResponsesPage, { + containerID: string, + query: FileListParams | null | undefined = {}, + options?: RequestOptions, + ): PagePromise { + return this._client.getAPIList(path`/containers/${containerID}/files`, CursorPage, { query, ...options, }); @@ -67,15 +60,16 @@ export class Files extends APIResource { /** * Delete Container File */ - del(containerId: string, fileId: string, options?: Core.RequestOptions): Core.APIPromise { - return this._client.delete(`/containers/${containerId}/files/${fileId}`, { + delete(fileID: string, params: FileDeleteParams, options?: RequestOptions): APIPromise { + const { container_id } = params; + return this._client.delete(path`/containers/${container_id}/files/${fileID}`, { ...options, - headers: { Accept: '*/*', ...options?.headers }, + headers: buildHeaders([{ Accept: '*/*' }, options?.headers]), }); } } -export class FileListResponsesPage extends CursorPage {} +export type FileListResponsesPage = CursorPage; export interface FileCreateResponse { /** @@ -192,7 +186,7 @@ export interface FileCreateParams { /** * The File object (not file name) to be uploaded. */ - file?: Core.Uploadable; + file?: Uploadable; /** * Name of the file to create. @@ -200,6 +194,10 @@ export interface FileCreateParams { file_id?: string; } +export interface FileRetrieveParams { + container_id: string; +} + export interface FileListParams extends CursorPageParams { /** * Sort order by the `created_at` timestamp of the objects. `asc` for ascending @@ -208,7 +206,10 @@ export interface FileListParams extends CursorPageParams { order?: 'asc' | 'desc'; } -Files.FileListResponsesPage = FileListResponsesPage; +export interface FileDeleteParams { + container_id: string; +} + Files.Content = Content; export declare namespace Files { @@ -216,10 +217,12 @@ export declare namespace Files { type FileCreateResponse as FileCreateResponse, type FileRetrieveResponse as FileRetrieveResponse, type FileListResponse as FileListResponse, - FileListResponsesPage as FileListResponsesPage, + type FileListResponsesPage as FileListResponsesPage, type FileCreateParams as FileCreateParams, + type FileRetrieveParams as FileRetrieveParams, type FileListParams as FileListParams, + type FileDeleteParams as FileDeleteParams, }; - export { Content as Content }; + export { Content as Content, type ContentRetrieveParams as ContentRetrieveParams }; } diff --git a/src/resources/containers/files/index.ts b/src/resources/containers/files/index.ts index 7305ab706..863f438c4 100644 --- a/src/resources/containers/files/index.ts +++ b/src/resources/containers/files/index.ts @@ -1,12 +1,14 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -export { Content } from './content'; +export { Content, type ContentRetrieveParams } from './content'; export { - FileListResponsesPage, Files, type FileCreateResponse, type FileRetrieveResponse, type FileListResponse, type FileCreateParams, + type FileRetrieveParams, type FileListParams, + type FileDeleteParams, + type FileListResponsesPage, } from './files'; diff --git a/src/resources/containers/index.ts b/src/resources/containers/index.ts index 91145bbe0..265451481 100644 --- a/src/resources/containers/index.ts +++ b/src/resources/containers/index.ts @@ -1,20 +1,22 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. export { - ContainerListResponsesPage, Containers, type ContainerCreateResponse, type ContainerRetrieveResponse, type ContainerListResponse, type ContainerCreateParams, type ContainerListParams, + type ContainerListResponsesPage, } from './containers'; export { - FileListResponsesPage, Files, type FileCreateResponse, type FileRetrieveResponse, type FileListResponse, type FileCreateParams, + type FileRetrieveParams, type FileListParams, + type FileDeleteParams, + type FileListResponsesPage, } from './files/index'; diff --git a/src/resources/embeddings.ts b/src/resources/embeddings.ts index fb02a7654..7a66904f7 100644 --- a/src/resources/embeddings.ts +++ b/src/resources/embeddings.ts @@ -1,7 +1,9 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { APIResource } from '../resource'; -import * as Core from '../core'; +import { APIResource } from '../core/resource'; +import { APIPromise } from '../core/api-promise'; +import { RequestOptions } from '../internal/request-options'; +import { loggerFor, toFloat32Array } from '../internal/utils'; export class Embeddings extends APIResource { /** @@ -16,10 +18,7 @@ export class Embeddings extends APIResource { * }); * ``` */ - create( - body: EmbeddingCreateParams, - options?: Core.RequestOptions, - ): Core.APIPromise { + create(body: EmbeddingCreateParams, options?: RequestOptions): APIPromise { const hasUserProvidedEncodingFormat = !!body.encoding_format; // No encoding_format specified, defaulting to base64 for performance reasons // See https://github.com/openai/openai-node/pull/1312 @@ -27,10 +26,10 @@ export class Embeddings extends APIResource { hasUserProvidedEncodingFormat ? body.encoding_format : 'base64'; if (hasUserProvidedEncodingFormat) { - Core.debug('Request', 'User defined encoding_format:', body.encoding_format); + loggerFor(this._client).debug('embeddings/user defined encoding_format:', body.encoding_format); } - const response: Core.APIPromise = this._client.post('/embeddings', { + const response: APIPromise = this._client.post('/embeddings', { body: { ...body, encoding_format: encoding_format as EmbeddingCreateParams['encoding_format'], @@ -47,13 +46,13 @@ export class Embeddings extends APIResource { // and we defaulted to base64 for performance reasons // we are sure then that the response is base64 encoded, let's decode it // the returned result will be a float32 array since this is OpenAI API's default encoding - Core.debug('response', 'Decoding base64 embeddings to float32 array'); + loggerFor(this._client).debug('embeddings/decoding base64 embeddings from base64'); - return (response as Core.APIPromise)._thenUnwrap((response) => { + return (response as APIPromise)._thenUnwrap((response) => { if (response && response.data) { response.data.forEach((embeddingBase64Obj) => { const embeddingBase64Str = embeddingBase64Obj.embedding as unknown as string; - embeddingBase64Obj.embedding = Core.toFloat32Array(embeddingBase64Str); + embeddingBase64Obj.embedding = toFloat32Array(embeddingBase64Str); }); } diff --git a/src/resources/evals/evals.ts b/src/resources/evals/evals.ts index 05a656619..cc563c78f 100644 --- a/src/resources/evals/evals.ts +++ b/src/resources/evals/evals.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 { APIResource } from '../../core/resource'; import * as Shared from '../shared'; import * as GraderModelsAPI from '../graders/grader-models'; import * as ResponsesAPI from '../responses/responses'; @@ -11,17 +9,23 @@ import { CreateEvalCompletionsRunDataSource, CreateEvalJSONLRunDataSource, EvalAPIError, + RunCancelParams, RunCancelResponse, RunCreateParams, RunCreateResponse, + RunDeleteParams, RunDeleteResponse, RunListParams, RunListResponse, RunListResponsesPage, + RunRetrieveParams, RunRetrieveResponse, Runs, } from './runs/runs'; -import { CursorPage, type CursorPageParams } from '../../pagination'; +import { APIPromise } from '../../core/api-promise'; +import { CursorPage, type CursorPageParams, PagePromise } from '../../core/pagination'; +import { RequestOptions } from '../../internal/request-options'; +import { path } from '../../internal/utils/path'; export class Evals extends APIResource { runs: RunsAPI.Runs = new RunsAPI.Runs(this._client); @@ -34,55 +38,43 @@ export class Evals extends APIResource { * We support several types of graders and datasources. For more information, see * the [Evals guide](https://platform.openai.com/docs/guides/evals). */ - create(body: EvalCreateParams, options?: Core.RequestOptions): Core.APIPromise { + create(body: EvalCreateParams, options?: RequestOptions): APIPromise { return this._client.post('/evals', { body, ...options }); } /** * Get an evaluation by ID. */ - retrieve(evalId: string, options?: Core.RequestOptions): Core.APIPromise { - return this._client.get(`/evals/${evalId}`, options); + retrieve(evalID: string, options?: RequestOptions): APIPromise { + return this._client.get(path`/evals/${evalID}`, options); } /** * Update certain properties of an evaluation. */ - update( - evalId: string, - body: EvalUpdateParams, - options?: Core.RequestOptions, - ): Core.APIPromise { - return this._client.post(`/evals/${evalId}`, { body, ...options }); + update(evalID: string, body: EvalUpdateParams, options?: RequestOptions): APIPromise { + return this._client.post(path`/evals/${evalID}`, { body, ...options }); } /** * List evaluations for a project. */ list( - query?: EvalListParams, - options?: Core.RequestOptions, - ): Core.PagePromise; - list(options?: Core.RequestOptions): Core.PagePromise; - list( - query: EvalListParams | Core.RequestOptions = {}, - options?: Core.RequestOptions, - ): Core.PagePromise { - if (isRequestOptions(query)) { - return this.list({}, query); - } - return this._client.getAPIList('/evals', EvalListResponsesPage, { query, ...options }); + query: EvalListParams | null | undefined = {}, + options?: RequestOptions, + ): PagePromise { + return this._client.getAPIList('/evals', CursorPage, { query, ...options }); } /** * Delete an evaluation. */ - del(evalId: string, options?: Core.RequestOptions): Core.APIPromise { - return this._client.delete(`/evals/${evalId}`, options); + delete(evalID: string, options?: RequestOptions): APIPromise { + return this._client.delete(path`/evals/${evalID}`, options); } } -export class EvalListResponsesPage extends CursorPage {} +export type EvalListResponsesPage = CursorPage; /** * A CustomDataSourceConfig which specifies the schema of your `item` and @@ -873,9 +865,7 @@ export interface EvalListParams extends CursorPageParams { order_by?: 'created_at' | 'updated_at'; } -Evals.EvalListResponsesPage = EvalListResponsesPage; Evals.Runs = Runs; -Evals.RunListResponsesPage = RunListResponsesPage; export declare namespace Evals { export { @@ -886,7 +876,7 @@ export declare namespace Evals { type EvalUpdateResponse as EvalUpdateResponse, type EvalListResponse as EvalListResponse, type EvalDeleteResponse as EvalDeleteResponse, - EvalListResponsesPage as EvalListResponsesPage, + type EvalListResponsesPage as EvalListResponsesPage, type EvalCreateParams as EvalCreateParams, type EvalUpdateParams as EvalUpdateParams, type EvalListParams as EvalListParams, @@ -902,8 +892,11 @@ export declare namespace Evals { type RunListResponse as RunListResponse, type RunDeleteResponse as RunDeleteResponse, type RunCancelResponse as RunCancelResponse, - RunListResponsesPage as RunListResponsesPage, + type RunListResponsesPage as RunListResponsesPage, type RunCreateParams as RunCreateParams, + type RunRetrieveParams as RunRetrieveParams, type RunListParams as RunListParams, + type RunDeleteParams as RunDeleteParams, + type RunCancelParams as RunCancelParams, }; } diff --git a/src/resources/evals/index.ts b/src/resources/evals/index.ts index b2627fbf3..cd74e0edc 100644 --- a/src/resources/evals/index.ts +++ b/src/resources/evals/index.ts @@ -1,7 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. export { - EvalListResponsesPage, Evals, type EvalCustomDataSourceConfig, type EvalStoredCompletionsDataSourceConfig, @@ -13,9 +12,9 @@ export { type EvalCreateParams, type EvalUpdateParams, type EvalListParams, + type EvalListResponsesPage, } from './evals'; export { - RunListResponsesPage, Runs, type CreateEvalCompletionsRunDataSource, type CreateEvalJSONLRunDataSource, @@ -26,5 +25,9 @@ export { type RunDeleteResponse, type RunCancelResponse, type RunCreateParams, + type RunRetrieveParams, type RunListParams, + type RunDeleteParams, + type RunCancelParams, + type RunListResponsesPage, } from './runs/index'; diff --git a/src/resources/evals/runs/index.ts b/src/resources/evals/runs/index.ts index d0e18bff4..e51e04c11 100644 --- a/src/resources/evals/runs/index.ts +++ b/src/resources/evals/runs/index.ts @@ -1,14 +1,14 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. export { - OutputItemListResponsesPage, OutputItems, type OutputItemRetrieveResponse, type OutputItemListResponse, + type OutputItemRetrieveParams, type OutputItemListParams, + type OutputItemListResponsesPage, } from './output-items'; export { - RunListResponsesPage, Runs, type CreateEvalCompletionsRunDataSource, type CreateEvalJSONLRunDataSource, @@ -19,5 +19,9 @@ export { type RunDeleteResponse, type RunCancelResponse, type RunCreateParams, + type RunRetrieveParams, type RunListParams, + type RunDeleteParams, + type RunCancelParams, + type RunListResponsesPage, } from './runs'; diff --git a/src/resources/evals/runs/output-items.ts b/src/resources/evals/runs/output-items.ts index ee947c60f..e7c33f27e 100644 --- a/src/resources/evals/runs/output-items.ts +++ b/src/resources/evals/runs/output-items.ts @@ -1,56 +1,43 @@ // 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 { APIResource } from '../../../core/resource'; import * as RunsAPI from './runs'; -import { CursorPage, type CursorPageParams } from '../../../pagination'; +import { APIPromise } from '../../../core/api-promise'; +import { CursorPage, type CursorPageParams, PagePromise } from '../../../core/pagination'; +import { RequestOptions } from '../../../internal/request-options'; +import { path } from '../../../internal/utils/path'; export class OutputItems extends APIResource { /** * Get an evaluation run output item by ID. */ retrieve( - evalId: string, - runId: string, - outputItemId: string, - options?: Core.RequestOptions, - ): Core.APIPromise { - return this._client.get(`/evals/${evalId}/runs/${runId}/output_items/${outputItemId}`, options); + outputItemID: string, + params: OutputItemRetrieveParams, + options?: RequestOptions, + ): APIPromise { + const { eval_id, run_id } = params; + return this._client.get(path`/evals/${eval_id}/runs/${run_id}/output_items/${outputItemID}`, options); } /** * Get a list of output items for an evaluation run. */ list( - evalId: string, - runId: string, - query?: OutputItemListParams, - options?: Core.RequestOptions, - ): Core.PagePromise; - list( - evalId: string, - runId: string, - options?: Core.RequestOptions, - ): Core.PagePromise; - list( - evalId: string, - runId: string, - query: OutputItemListParams | Core.RequestOptions = {}, - options?: Core.RequestOptions, - ): Core.PagePromise { - if (isRequestOptions(query)) { - return this.list(evalId, runId, {}, query); - } + runID: string, + params: OutputItemListParams, + options?: RequestOptions, + ): PagePromise { + const { eval_id, ...query } = params; return this._client.getAPIList( - `/evals/${evalId}/runs/${runId}/output_items`, - OutputItemListResponsesPage, + path`/evals/${eval_id}/runs/${runID}/output_items`, + CursorPage, { query, ...options }, ); } } -export class OutputItemListResponsesPage extends CursorPage {} +export type OutputItemListResponsesPage = CursorPage; /** * A schema representing an evaluation run output item. @@ -384,27 +371,43 @@ export namespace OutputItemListResponse { } } +export interface OutputItemRetrieveParams { + /** + * The ID of the evaluation to retrieve runs for. + */ + eval_id: string; + + /** + * The ID of the run to retrieve. + */ + run_id: string; +} + export interface OutputItemListParams extends CursorPageParams { /** - * Sort order for output items by timestamp. Use `asc` for ascending order or - * `desc` for descending order. Defaults to `asc`. + * Path param: The ID of the evaluation to retrieve runs for. + */ + eval_id: string; + + /** + * Query param: Sort order for output items by timestamp. Use `asc` for ascending + * order or `desc` for descending order. Defaults to `asc`. */ order?: 'asc' | 'desc'; /** - * Filter output items by status. Use `failed` to filter by failed output items or - * `pass` to filter by passed output items. + * Query param: Filter output items by status. Use `failed` to filter by failed + * output items or `pass` to filter by passed output items. */ status?: 'fail' | 'pass'; } -OutputItems.OutputItemListResponsesPage = OutputItemListResponsesPage; - export declare namespace OutputItems { export { type OutputItemRetrieveResponse as OutputItemRetrieveResponse, type OutputItemListResponse as OutputItemListResponse, - OutputItemListResponsesPage as OutputItemListResponsesPage, + type OutputItemListResponsesPage as OutputItemListResponsesPage, + type OutputItemRetrieveParams as OutputItemRetrieveParams, type OutputItemListParams as OutputItemListParams, }; } diff --git a/src/resources/evals/runs/runs.ts b/src/resources/evals/runs/runs.ts index e761e2160..55cff4f93 100644 --- a/src/resources/evals/runs/runs.ts +++ b/src/resources/evals/runs/runs.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 { APIResource } from '../../../core/resource'; import * as Shared from '../../shared'; import * as ResponsesAPI from '../../responses/responses'; import * as OutputItemsAPI from './output-items'; @@ -10,10 +8,14 @@ import { OutputItemListParams, OutputItemListResponse, OutputItemListResponsesPage, + OutputItemRetrieveParams, OutputItemRetrieveResponse, OutputItems, } from './output-items'; -import { CursorPage, type CursorPageParams } from '../../../pagination'; +import { APIPromise } from '../../../core/api-promise'; +import { CursorPage, type CursorPageParams, PagePromise } from '../../../core/pagination'; +import { RequestOptions } from '../../../internal/request-options'; +import { path } from '../../../internal/utils/path'; export class Runs extends APIResource { outputItems: OutputItemsAPI.OutputItems = new OutputItemsAPI.OutputItems(this._client); @@ -23,64 +25,54 @@ export class Runs extends APIResource { * model configuration to use to test. The datasource will be validated against the * schema specified in the config of the evaluation. */ - create( - evalId: string, - body: RunCreateParams, - options?: Core.RequestOptions, - ): Core.APIPromise { - return this._client.post(`/evals/${evalId}/runs`, { body, ...options }); + create(evalID: string, body: RunCreateParams, options?: RequestOptions): APIPromise { + return this._client.post(path`/evals/${evalID}/runs`, { body, ...options }); } /** * Get an evaluation run by ID. */ retrieve( - evalId: string, - runId: string, - options?: Core.RequestOptions, - ): Core.APIPromise { - return this._client.get(`/evals/${evalId}/runs/${runId}`, options); + runID: string, + params: RunRetrieveParams, + options?: RequestOptions, + ): APIPromise { + const { eval_id } = params; + return this._client.get(path`/evals/${eval_id}/runs/${runID}`, options); } /** * Get a list of runs for an evaluation. */ list( - evalId: string, - query?: RunListParams, - options?: Core.RequestOptions, - ): Core.PagePromise; - list( - evalId: string, - options?: Core.RequestOptions, - ): Core.PagePromise; - list( - evalId: string, - query: RunListParams | Core.RequestOptions = {}, - options?: Core.RequestOptions, - ): Core.PagePromise { - if (isRequestOptions(query)) { - return this.list(evalId, {}, query); - } - return this._client.getAPIList(`/evals/${evalId}/runs`, RunListResponsesPage, { query, ...options }); + evalID: string, + query: RunListParams | null | undefined = {}, + options?: RequestOptions, + ): PagePromise { + return this._client.getAPIList(path`/evals/${evalID}/runs`, CursorPage, { + query, + ...options, + }); } /** * Delete an eval run. */ - del(evalId: string, runId: string, options?: Core.RequestOptions): Core.APIPromise { - return this._client.delete(`/evals/${evalId}/runs/${runId}`, options); + delete(runID: string, params: RunDeleteParams, options?: RequestOptions): APIPromise { + const { eval_id } = params; + return this._client.delete(path`/evals/${eval_id}/runs/${runID}`, options); } /** * Cancel an ongoing evaluation run. */ - cancel(evalId: string, runId: string, options?: Core.RequestOptions): Core.APIPromise { - return this._client.post(`/evals/${evalId}/runs/${runId}`, options); + cancel(runID: string, params: RunCancelParams, options?: RequestOptions): APIPromise { + const { eval_id } = params; + return this._client.post(path`/evals/${eval_id}/runs/${runID}`, options); } } -export class RunListResponsesPage extends CursorPage {} +export type RunListResponsesPage = CursorPage; /** * A CompletionsRunDataSource object describing a model sampling configuration. @@ -2185,6 +2177,13 @@ export namespace RunCreateParams { } } +export interface RunRetrieveParams { + /** + * The ID of the evaluation to retrieve runs for. + */ + eval_id: string; +} + export interface RunListParams extends CursorPageParams { /** * Sort order for runs by timestamp. Use `asc` for ascending order or `desc` for @@ -2199,9 +2198,21 @@ export interface RunListParams extends CursorPageParams { status?: 'queued' | 'in_progress' | 'completed' | 'canceled' | 'failed'; } -Runs.RunListResponsesPage = RunListResponsesPage; +export interface RunDeleteParams { + /** + * The ID of the evaluation to delete the run from. + */ + eval_id: string; +} + +export interface RunCancelParams { + /** + * The ID of the evaluation whose run you want to cancel. + */ + eval_id: string; +} + Runs.OutputItems = OutputItems; -Runs.OutputItemListResponsesPage = OutputItemListResponsesPage; export declare namespace Runs { export { @@ -2213,16 +2224,20 @@ export declare namespace Runs { type RunListResponse as RunListResponse, type RunDeleteResponse as RunDeleteResponse, type RunCancelResponse as RunCancelResponse, - RunListResponsesPage as RunListResponsesPage, + type RunListResponsesPage as RunListResponsesPage, type RunCreateParams as RunCreateParams, + type RunRetrieveParams as RunRetrieveParams, type RunListParams as RunListParams, + type RunDeleteParams as RunDeleteParams, + type RunCancelParams as RunCancelParams, }; export { OutputItems as OutputItems, type OutputItemRetrieveResponse as OutputItemRetrieveResponse, type OutputItemListResponse as OutputItemListResponse, - OutputItemListResponsesPage as OutputItemListResponsesPage, + type OutputItemListResponsesPage as OutputItemListResponsesPage, + type OutputItemRetrieveParams as OutputItemRetrieveParams, type OutputItemListParams as OutputItemListParams, }; } diff --git a/src/resources/files.ts b/src/resources/files.ts index 723ac4cde..e0b66b77a 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 { APIResource } from '../core/resource'; +import { APIPromise } from '../core/api-promise'; +import { CursorPage, type CursorPageParams, PagePromise } from '../core/pagination'; +import { type Uploadable } from '../core/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,59 +35,45 @@ 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`, { + content(fileID: string, options?: RequestOptions): APIPromise { + return this._client.get(path`/files/${fileID}/content`, { ...options, - headers: { Accept: 'application/binary', ...options?.headers }, + headers: buildHeaders([{ Accept: 'application/binary' }, options?.headers]), __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`, options); - } - /** * Waits for the given file to be processed, default timeout is 30 mins. */ @@ -112,7 +101,7 @@ export class Files extends APIResource { } } -export class FileObjectsPage extends CursorPage {} +export type FileObjectsPage = CursorPage; export type FileContent = string; @@ -197,7 +186,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. One of: - `assistants`: Used in the @@ -221,15 +210,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.ts b/src/resources/fine-tuning.ts new file mode 100644 index 000000000..01fd61342 --- /dev/null +++ b/src/resources/fine-tuning.ts @@ -0,0 +1,3 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export * from './fine-tuning/index'; diff --git a/src/resources/fine-tuning/alpha/alpha.ts b/src/resources/fine-tuning/alpha/alpha.ts index 77d695195..5a77065e8 100644 --- a/src/resources/fine-tuning/alpha/alpha.ts +++ b/src/resources/fine-tuning/alpha/alpha.ts @@ -1,6 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { APIResource } from '../../../resource'; +import { APIResource } from '../../../core/resource'; import * as GradersAPI from './graders'; import { GraderRunParams, diff --git a/src/resources/fine-tuning/alpha/graders.ts b/src/resources/fine-tuning/alpha/graders.ts index a9ef57f71..043511703 100644 --- a/src/resources/fine-tuning/alpha/graders.ts +++ b/src/resources/fine-tuning/alpha/graders.ts @@ -1,8 +1,9 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { APIResource } from '../../../resource'; -import * as Core from '../../../core'; +import { APIResource } from '../../../core/resource'; import * as GraderModelsAPI from '../../graders/grader-models'; +import { APIPromise } from '../../../core/api-promise'; +import { RequestOptions } from '../../../internal/request-options'; export class Graders extends APIResource { /** @@ -23,7 +24,7 @@ export class Graders extends APIResource { * }); * ``` */ - run(body: GraderRunParams, options?: Core.RequestOptions): Core.APIPromise { + run(body: GraderRunParams, options?: RequestOptions): APIPromise { return this._client.post('/fine_tuning/alpha/graders/run', { body, ...options }); } @@ -44,10 +45,7 @@ export class Graders extends APIResource { * }); * ``` */ - validate( - body: GraderValidateParams, - options?: Core.RequestOptions, - ): Core.APIPromise { + validate(body: GraderValidateParams, options?: RequestOptions): APIPromise { return this._client.post('/fine_tuning/alpha/graders/validate', { body, ...options }); } } diff --git a/src/resources/fine-tuning/checkpoints/checkpoints.ts b/src/resources/fine-tuning/checkpoints/checkpoints.ts index 08422aa64..da055b0e4 100644 --- a/src/resources/fine-tuning/checkpoints/checkpoints.ts +++ b/src/resources/fine-tuning/checkpoints/checkpoints.ts @@ -1,11 +1,12 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { APIResource } from '../../../resource'; +import { APIResource } from '../../../core/resource'; import * as PermissionsAPI from './permissions'; import { PermissionCreateParams, PermissionCreateResponse, PermissionCreateResponsesPage, + PermissionDeleteParams, PermissionDeleteResponse, PermissionRetrieveParams, PermissionRetrieveResponse, @@ -17,7 +18,6 @@ export class Checkpoints extends APIResource { } Checkpoints.Permissions = Permissions; -Checkpoints.PermissionCreateResponsesPage = PermissionCreateResponsesPage; export declare namespace Checkpoints { export { @@ -25,8 +25,9 @@ export declare namespace Checkpoints { type PermissionCreateResponse as PermissionCreateResponse, type PermissionRetrieveResponse as PermissionRetrieveResponse, type PermissionDeleteResponse as PermissionDeleteResponse, - PermissionCreateResponsesPage as PermissionCreateResponsesPage, + type PermissionCreateResponsesPage as PermissionCreateResponsesPage, type PermissionCreateParams as PermissionCreateParams, type PermissionRetrieveParams as PermissionRetrieveParams, + type PermissionDeleteParams as PermissionDeleteParams, }; } diff --git a/src/resources/fine-tuning/checkpoints/index.ts b/src/resources/fine-tuning/checkpoints/index.ts index 51d1af9cf..7e04fc667 100644 --- a/src/resources/fine-tuning/checkpoints/index.ts +++ b/src/resources/fine-tuning/checkpoints/index.ts @@ -2,11 +2,12 @@ export { Checkpoints } from './checkpoints'; export { - PermissionCreateResponsesPage, Permissions, type PermissionCreateResponse, type PermissionRetrieveResponse, type PermissionDeleteResponse, type PermissionCreateParams, type PermissionRetrieveParams, + type PermissionDeleteParams, + type PermissionCreateResponsesPage, } from './permissions'; diff --git a/src/resources/fine-tuning/checkpoints/permissions.ts b/src/resources/fine-tuning/checkpoints/permissions.ts index dc25bab7f..9217f324c 100644 --- a/src/resources/fine-tuning/checkpoints/permissions.ts +++ b/src/resources/fine-tuning/checkpoints/permissions.ts @@ -1,9 +1,10 @@ // 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 { Page } from '../../../pagination'; +import { APIResource } from '../../../core/resource'; +import { APIPromise } from '../../../core/api-promise'; +import { Page, PagePromise } from '../../../core/pagination'; +import { RequestOptions } from '../../../internal/request-options'; +import { path } from '../../../internal/utils/path'; export class Permissions extends APIResource { /** @@ -26,11 +27,11 @@ export class Permissions extends APIResource { create( fineTunedModelCheckpoint: string, body: PermissionCreateParams, - options?: Core.RequestOptions, - ): Core.PagePromise { + options?: RequestOptions, + ): PagePromise { return this._client.getAPIList( - `/fine_tuning/checkpoints/${fineTunedModelCheckpoint}/permissions`, - PermissionCreateResponsesPage, + path`/fine_tuning/checkpoints/${fineTunedModelCheckpoint}/permissions`, + Page, { body, method: 'post', ...options }, ); } @@ -51,22 +52,10 @@ export class Permissions extends APIResource { */ retrieve( fineTunedModelCheckpoint: string, - query?: PermissionRetrieveParams, - options?: Core.RequestOptions, - ): Core.APIPromise; - retrieve( - fineTunedModelCheckpoint: string, - options?: Core.RequestOptions, - ): Core.APIPromise; - retrieve( - fineTunedModelCheckpoint: string, - query: PermissionRetrieveParams | Core.RequestOptions = {}, - options?: Core.RequestOptions, - ): Core.APIPromise { - if (isRequestOptions(query)) { - return this.retrieve(fineTunedModelCheckpoint, {}, query); - } - return this._client.get(`/fine_tuning/checkpoints/${fineTunedModelCheckpoint}/permissions`, { + query: PermissionRetrieveParams | null | undefined = {}, + options?: RequestOptions, + ): APIPromise { + return this._client.get(path`/fine_tuning/checkpoints/${fineTunedModelCheckpoint}/permissions`, { query, ...options, }); @@ -81,28 +70,30 @@ export class Permissions extends APIResource { * @example * ```ts * const permission = - * await client.fineTuning.checkpoints.permissions.del( - * 'ft:gpt-4o-mini-2024-07-18:org:weather:B7R9VjQd', + * await client.fineTuning.checkpoints.permissions.delete( * 'cp_zc4Q7MP6XxulcVzj4MZdwsAB', + * { + * fine_tuned_model_checkpoint: + * 'ft:gpt-4o-mini-2024-07-18:org:weather:B7R9VjQd', + * }, * ); * ``` */ - del( - fineTunedModelCheckpoint: string, - permissionId: string, - options?: Core.RequestOptions, - ): Core.APIPromise { + delete( + permissionID: string, + params: PermissionDeleteParams, + options?: RequestOptions, + ): APIPromise { + const { fine_tuned_model_checkpoint } = params; return this._client.delete( - `/fine_tuning/checkpoints/${fineTunedModelCheckpoint}/permissions/${permissionId}`, + path`/fine_tuning/checkpoints/${fine_tuned_model_checkpoint}/permissions/${permissionID}`, options, ); } } -/** - * Note: no pagination actually occurs yet, this is for forwards-compatibility. - */ -export class PermissionCreateResponsesPage extends Page {} +// Note: no pagination actually occurs yet, this is for forwards-compatibility. +export type PermissionCreateResponsesPage = Page; /** * The `checkpoint.permission` object represents a permission for a fine-tuned @@ -216,15 +207,21 @@ export interface PermissionRetrieveParams { project_id?: string; } -Permissions.PermissionCreateResponsesPage = PermissionCreateResponsesPage; +export interface PermissionDeleteParams { + /** + * The ID of the fine-tuned model checkpoint to delete a permission for. + */ + fine_tuned_model_checkpoint: string; +} export declare namespace Permissions { export { type PermissionCreateResponse as PermissionCreateResponse, type PermissionRetrieveResponse as PermissionRetrieveResponse, type PermissionDeleteResponse as PermissionDeleteResponse, - PermissionCreateResponsesPage as PermissionCreateResponsesPage, + type PermissionCreateResponsesPage as PermissionCreateResponsesPage, type PermissionCreateParams as PermissionCreateParams, type PermissionRetrieveParams as PermissionRetrieveParams, + type PermissionDeleteParams as PermissionDeleteParams, }; } diff --git a/src/resources/fine-tuning/fine-tuning.ts b/src/resources/fine-tuning/fine-tuning.ts index 8fb54983b..11d441754 100644 --- a/src/resources/fine-tuning/fine-tuning.ts +++ b/src/resources/fine-tuning/fine-tuning.ts @@ -1,6 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { APIResource } from '../../resource'; +import { APIResource } from '../../core/resource'; import * as MethodsAPI from './methods'; import { DpoHyperparameters, @@ -39,8 +39,6 @@ export class FineTuning extends APIResource { FineTuning.Methods = Methods; FineTuning.Jobs = Jobs; -FineTuning.FineTuningJobsPage = FineTuningJobsPage; -FineTuning.FineTuningJobEventsPage = FineTuningJobEventsPage; FineTuning.Checkpoints = Checkpoints; FineTuning.Alpha = Alpha; @@ -59,11 +57,11 @@ export declare namespace FineTuning { Jobs as Jobs, type FineTuningJob as FineTuningJob, type FineTuningJobEvent as FineTuningJobEvent, - type FineTuningJobIntegration as FineTuningJobIntegration, type FineTuningJobWandbIntegration as FineTuningJobWandbIntegration, type FineTuningJobWandbIntegrationObject as FineTuningJobWandbIntegrationObject, - FineTuningJobsPage as FineTuningJobsPage, - FineTuningJobEventsPage as FineTuningJobEventsPage, + type FineTuningJobIntegration as FineTuningJobIntegration, + 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 878ac402d..8d4f240f2 100644 --- a/src/resources/fine-tuning/index.ts +++ b/src/resources/fine-tuning/index.ts @@ -4,17 +4,17 @@ export { Alpha } from './alpha/index'; export { Checkpoints } from './checkpoints/index'; export { FineTuning } from './fine-tuning'; export { - FineTuningJobsPage, - FineTuningJobEventsPage, Jobs, type FineTuningJob, type FineTuningJobEvent, - type FineTuningJobIntegration, type FineTuningJobWandbIntegration, type FineTuningJobWandbIntegrationObject, + type FineTuningJobIntegration, type JobCreateParams, type JobListParams, type JobListEventsParams, + type FineTuningJobsPage, + type FineTuningJobEventsPage, } from './jobs/index'; export { Methods, diff --git a/src/resources/fine-tuning/jobs.ts b/src/resources/fine-tuning/jobs.ts new file mode 100644 index 000000000..6640de1f2 --- /dev/null +++ b/src/resources/fine-tuning/jobs.ts @@ -0,0 +1,3 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export * from './jobs/index'; diff --git a/src/resources/fine-tuning/jobs/checkpoints.ts b/src/resources/fine-tuning/jobs/checkpoints.ts index 10902e715..868713b6d 100644 --- a/src/resources/fine-tuning/jobs/checkpoints.ts +++ b/src/resources/fine-tuning/jobs/checkpoints.ts @@ -1,9 +1,9 @@ // 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 { APIResource } from '../../../core/resource'; +import { CursorPage, type CursorPageParams, PagePromise } from '../../../core/pagination'; +import { RequestOptions } from '../../../internal/request-options'; +import { path } from '../../../internal/utils/path'; export class Checkpoints extends APIResource { /** @@ -20,31 +20,19 @@ export class Checkpoints extends APIResource { * ``` */ 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 @@ -110,12 +98,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..18a2b1a93 100644 --- a/src/resources/fine-tuning/jobs/index.ts +++ b/src/resources/fine-tuning/jobs/index.ts @@ -1,21 +1,21 @@ // 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, - type FineTuningJobIntegration, type FineTuningJobWandbIntegration, type FineTuningJobWandbIntegrationObject, + type FineTuningJobIntegration, 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 cc5f55e9a..c1ed972c2 100644 --- a/src/resources/fine-tuning/jobs/jobs.ts +++ b/src/resources/fine-tuning/jobs/jobs.ts @@ -1,8 +1,7 @@ // 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 { APIResource } from '../../../core/resource'; +import * as Shared from '../../shared'; import * as MethodsAPI from '../methods'; import * as CheckpointsAPI from './checkpoints'; import { @@ -11,7 +10,10 @@ import { FineTuningJobCheckpoint, FineTuningJobCheckpointsPage, } from './checkpoints'; -import { CursorPage, type CursorPageParams } from '../../../pagination'; +import { APIPromise } from '../../../core/api-promise'; +import { CursorPage, type CursorPageParams, PagePromise } from '../../../core/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); @@ -33,7 +35,7 @@ export class Jobs extends APIResource { * }); * ``` */ - create(body: JobCreateParams, options?: Core.RequestOptions): Core.APIPromise { + create(body: JobCreateParams, options?: RequestOptions): APIPromise { return this._client.post('/fine_tuning/jobs', { body, ...options }); } @@ -49,8 +51,8 @@ export class Jobs extends APIResource { * ); * ``` */ - 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); } /** @@ -65,18 +67,10 @@ export class Jobs extends APIResource { * ``` */ 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 }); } /** @@ -89,8 +83,8 @@ export class Jobs extends APIResource { * ); * ``` */ - 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); } /** @@ -107,26 +101,15 @@ export class Jobs extends APIResource { * ``` */ 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 }, + ); } /** @@ -139,8 +122,8 @@ export class Jobs extends APIResource { * ); * ``` */ - pause(fineTuningJobId: string, options?: Core.RequestOptions): Core.APIPromise { - return this._client.post(`/fine_tuning/jobs/${fineTuningJobId}/pause`, options); + pause(fineTuningJobID: string, options?: RequestOptions): APIPromise { + return this._client.post(path`/fine_tuning/jobs/${fineTuningJobID}/pause`, options); } /** @@ -153,14 +136,14 @@ export class Jobs extends APIResource { * ); * ``` */ - resume(fineTuningJobId: string, options?: Core.RequestOptions): Core.APIPromise { - return this._client.post(`/fine_tuning/jobs/${fineTuningJobId}/resume`, options); + resume(fineTuningJobID: string, options?: RequestOptions): APIPromise { + return this._client.post(path`/fine_tuning/jobs/${fineTuningJobID}/resume`, 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 @@ -264,6 +247,16 @@ export interface FineTuningJob { */ integrations?: 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, 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 method used for fine-tuning. */ @@ -383,8 +376,6 @@ export interface FineTuningJobEvent { type?: 'message' | 'metrics'; } -export type FineTuningJobIntegration = FineTuningJobWandbIntegrationObject; - /** * The settings for your integration with Weights and Biases. This payload * specifies the project that metrics will be sent to. Optionally, you can set an @@ -433,6 +424,8 @@ export interface FineTuningJobWandbIntegrationObject { wandb: FineTuningJobWandbIntegration; } +export type FineTuningJobIntegration = FineTuningJobWandbIntegrationObject; + export interface JobCreateParams { /** * The name of the model to fine-tune. You can select one of the @@ -473,6 +466,16 @@ export interface JobCreateParams { */ integrations?: 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, 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 method used for fine-tuning. */ @@ -614,24 +617,27 @@ export namespace JobCreateParams { } } -export interface JobListParams extends CursorPageParams {} +export interface JobListParams extends CursorPageParams { + /** + * Optional metadata filter. To filter, use the syntax `metadata[k]=v`. + * Alternatively, set `metadata=null` to indicate no metadata. + */ + metadata?: Record | null; +} export interface JobListEventsParams extends CursorPageParams {} -Jobs.FineTuningJobsPage = FineTuningJobsPage; -Jobs.FineTuningJobEventsPage = FineTuningJobEventsPage; Jobs.Checkpoints = Checkpoints; -Jobs.FineTuningJobCheckpointsPage = FineTuningJobCheckpointsPage; export declare namespace Jobs { export { type FineTuningJob as FineTuningJob, type FineTuningJobEvent as FineTuningJobEvent, - type FineTuningJobIntegration as FineTuningJobIntegration, type FineTuningJobWandbIntegration as FineTuningJobWandbIntegration, type FineTuningJobWandbIntegrationObject as FineTuningJobWandbIntegrationObject, - FineTuningJobsPage as FineTuningJobsPage, - FineTuningJobEventsPage as FineTuningJobEventsPage, + type FineTuningJobIntegration as FineTuningJobIntegration, + type FineTuningJobsPage as FineTuningJobsPage, + type FineTuningJobEventsPage as FineTuningJobEventsPage, type JobCreateParams as JobCreateParams, type JobListParams as JobListParams, type JobListEventsParams as JobListEventsParams, @@ -640,7 +646,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/fine-tuning/methods.ts b/src/resources/fine-tuning/methods.ts index aa459c74c..9c78d584b 100644 --- a/src/resources/fine-tuning/methods.ts +++ b/src/resources/fine-tuning/methods.ts @@ -1,6 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { APIResource } from '../../resource'; +import { APIResource } from '../../core/resource'; import * as GraderModelsAPI from '../graders/grader-models'; export class Methods extends APIResource {} diff --git a/src/resources/graders/grader-models.ts b/src/resources/graders/grader-models.ts index d2c335300..2b08d3d14 100644 --- a/src/resources/graders/grader-models.ts +++ b/src/resources/graders/grader-models.ts @@ -1,6 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { APIResource } from '../../resource'; +import { APIResource } from '../../core/resource'; import * as ResponsesAPI from '../responses/responses'; export class GraderModels extends APIResource {} diff --git a/src/resources/graders/graders.ts b/src/resources/graders/graders.ts index de3297450..d337e02ae 100644 --- a/src/resources/graders/graders.ts +++ b/src/resources/graders/graders.ts @@ -1,6 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { APIResource } from '../../resource'; +import { APIResource } from '../../core/resource'; import * as GraderModelsAPI from './grader-models'; import { GraderModels, diff --git a/src/resources/images.ts b/src/resources/images.ts index c6b14833a..9b7bacf87 100644 --- a/src/resources/images.ts +++ b/src/resources/images.ts @@ -1,7 +1,10 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { APIResource } from '../resource'; -import * as Core from '../core'; +import { APIResource } from '../core/resource'; +import { APIPromise } from '../core/api-promise'; +import { type Uploadable } from '../core/uploads'; +import { RequestOptions } from '../internal/request-options'; +import { multipartFormRequestOptions } from '../internal/uploads'; export class Images extends APIResource { /** @@ -14,11 +17,11 @@ export class Images extends APIResource { * }); * ``` */ - 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), + ); } /** @@ -33,8 +36,11 @@ export class Images extends APIResource { * }); * ``` */ - 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), + ); } /** @@ -48,7 +54,7 @@ export class Images extends APIResource { * }); * ``` */ - generate(body: ImageGenerateParams, options?: Core.RequestOptions): Core.APIPromise { + generate(body: ImageGenerateParams, options?: RequestOptions): APIPromise { return this._client.post('/images/generations', { body, ...options }); } } @@ -148,7 +154,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 @@ -192,7 +198,7 @@ export interface ImageEditParams { * For `dall-e-2`, you can only provide one image, and it should be a square `png` * file less than 4MB. */ - image: Core.Uploadable | Array; + image: Uploadable | Array; /** * A text description of the desired image(s). The maximum length is 1000 @@ -217,7 +223,7 @@ export interface ImageEditParams { * the mask will be applied on the first image. 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` and `gpt-image-1` are diff --git a/src/resources/index.ts b/src/resources/index.ts index d1f816a84..d64befac9 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 { @@ -23,13 +23,13 @@ export { type CompletionCreateParamsStreaming, } from './completions'; export { - ContainerListResponsesPage, Containers, type ContainerCreateResponse, type ContainerRetrieveResponse, type ContainerListResponse, type ContainerCreateParams, type ContainerListParams, + type ContainerListResponsesPage, } from './containers/containers'; export { Embeddings, @@ -39,7 +39,6 @@ export { type EmbeddingCreateParams, } from './embeddings'; export { - EvalListResponsesPage, Evals, type EvalCustomDataSourceConfig, type EvalStoredCompletionsDataSourceConfig, @@ -51,9 +50,9 @@ export { type EvalCreateParams, type EvalUpdateParams, type EvalListParams, + type EvalListResponsesPage, } from './evals/evals'; export { - FileObjectsPage, Files, type FileContent, type FileDeleted, @@ -61,6 +60,7 @@ export { type FilePurpose, type FileCreateParams, type FileListParams, + type FileObjectsPage, } from './files'; export { FineTuning } from './fine-tuning/fine-tuning'; export { Graders } from './graders/graders'; @@ -73,7 +73,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, @@ -87,8 +87,6 @@ export { export { Responses } from './responses/responses'; export { Uploads, type Upload, type UploadCreateParams, type UploadCompleteParams } from './uploads/uploads'; export { - VectorStoresPage, - VectorStoreSearchResponsesPage, VectorStores, type AutoFileChunkingStrategyParam, type FileChunkingStrategy, @@ -104,4 +102,6 @@ export { type VectorStoreUpdateParams, type VectorStoreListParams, type VectorStoreSearchParams, + type VectorStoresPage, + type VectorStoreSearchResponsesPage, } from './vector-stores/vector-stores'; diff --git a/src/resources/models.ts b/src/resources/models.ts index 6d8cd5296..25a730ebf 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 { APIResource } from '../core/resource'; +import { APIPromise } from '../core/api-promise'; +import { Page, PagePromise } from '../core/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 86e90376d..2792e0f30 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 { APIResource } from '../core/resource'; +import { APIPromise } from '../core/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 }); } } diff --git a/src/resources/responses.ts b/src/resources/responses.ts new file mode 100644 index 000000000..9d26aac0c --- /dev/null +++ b/src/resources/responses.ts @@ -0,0 +1,3 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export * from './responses/index'; diff --git a/src/resources/responses/input-items.ts b/src/resources/responses/input-items.ts index 211b6a7b6..9ff116448 100644 --- a/src/resources/responses/input-items.ts +++ b/src/resources/responses/input-items.ts @@ -1,11 +1,11 @@ // 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 { APIResource } from '../../core/resource'; import * as ResponsesAPI from './responses'; import { ResponseItemsPage } from './responses'; -import { type CursorPageParams } from '../../pagination'; +import { CursorPage, type CursorPageParams, PagePromise } from '../../core/pagination'; +import { RequestOptions } from '../../internal/request-options'; +import { path } from '../../internal/utils/path'; export class InputItems extends APIResource { /** @@ -22,26 +22,15 @@ export class InputItems extends APIResource { * ``` */ list( - responseId: string, - query?: InputItemListParams, - options?: Core.RequestOptions, - ): Core.PagePromise; - list( - responseId: string, - options?: Core.RequestOptions, - ): Core.PagePromise; - list( - responseId: string, - query: InputItemListParams | Core.RequestOptions = {}, - options?: Core.RequestOptions, - ): Core.PagePromise { - if (isRequestOptions(query)) { - return this.list(responseId, {}, query); - } - return this._client.getAPIList(`/responses/${responseId}/input_items`, ResponseItemsPage, { - query, - ...options, - }); + responseID: string, + query: InputItemListParams | null | undefined = {}, + options?: RequestOptions, + ): PagePromise { + return this._client.getAPIList( + path`/responses/${responseID}/input_items`, + CursorPage, + { query, ...options }, + ); } } @@ -100,4 +89,4 @@ export declare namespace InputItems { export { type ResponseItemList as ResponseItemList, type InputItemListParams as InputItemListParams }; } -export { ResponseItemsPage }; +export { type ResponseItemsPage }; diff --git a/src/resources/responses/input-items.ts.orig b/src/resources/responses/input-items.ts.orig deleted file mode 100644 index 470740b61..000000000 --- a/src/resources/responses/input-items.ts.orig +++ /dev/null @@ -1,114 +0,0 @@ -// 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 ResponsesAPI from './responses'; -import { ResponseItemsPage } from './responses'; -import { type CursorPageParams } from '../../pagination'; - -export class InputItems extends APIResource { - /** - * Returns a list of input items for a given response. - */ - list( - responseId: string, - query?: InputItemListParams, - options?: Core.RequestOptions, - ): Core.PagePromise; - list( - responseId: string, - options?: Core.RequestOptions, - ): Core.PagePromise; - list( - responseId: string, - query: InputItemListParams | Core.RequestOptions = {}, - options?: Core.RequestOptions, - ): Core.PagePromise { - if (isRequestOptions(query)) { - return this.list(responseId, {}, query); - } - return this._client.getAPIList(`/responses/${responseId}/input_items`, ResponseItemsPage, { - query, - ...options, - }); - } -} - -<<<<<<< HEAD -export class ResponseItemListDataPage extends CursorPage< - // @ts-ignore some items don't necessarily have the `id` property - | ResponseItemList.Message - | ResponsesAPI.ResponseOutputMessage - | ResponsesAPI.ResponseFileSearchToolCall - | ResponsesAPI.ResponseComputerToolCall - | ResponseItemList.ComputerCallOutput - | ResponsesAPI.ResponseFunctionWebSearch - | ResponsesAPI.ResponseFunctionToolCall - | ResponseItemList.FunctionCallOutput -> {} - -||||||| parent of e5ea4a71 (fix(types): improve responses type names (#1392)) -export class ResponseItemListDataPage extends CursorPage< - | ResponseItemList.Message - | ResponsesAPI.ResponseOutputMessage - | ResponsesAPI.ResponseFileSearchToolCall - | ResponsesAPI.ResponseComputerToolCall - | ResponseItemList.ComputerCallOutput - | ResponsesAPI.ResponseFunctionWebSearch - | ResponsesAPI.ResponseFunctionToolCall - | ResponseItemList.FunctionCallOutput -> {} - -======= ->>>>>>> e5ea4a71 (fix(types): improve responses type names (#1392)) -/** - * A list of Response items. - */ -export interface ResponseItemList { - /** - * A list of items used to generate this response. - */ - data: Array; - - /** - * The ID of the first item in the list. - */ - first_id: string; - - /** - * Whether there are more items available. - */ - has_more: boolean; - - /** - * The ID of the last item in the list. - */ - last_id: string; - - /** - * The type of object returned, must be `list`. - */ - object: 'list'; -} - -export interface InputItemListParams extends CursorPageParams { - /** - * An item ID to list items before, used in pagination. - */ - before?: string; - - /** - * The order to return the input items in. Default is `asc`. - * - * - `asc`: Return the input items in ascending order. - * - `desc`: Return the input items in descending order. - */ - order?: 'asc' | 'desc'; -} - -export declare namespace InputItems { - export { type ResponseItemList as ResponseItemList, type InputItemListParams as InputItemListParams }; -} - -export { ResponseItemsPage }; diff --git a/src/resources/responses/responses.ts b/src/resources/responses/responses.ts index eeaff8a11..e5400dcea 100644 --- a/src/resources/responses/responses.ts +++ b/src/resources/responses/responses.ts @@ -6,16 +6,18 @@ import { type ResponseCreateParamsWithTools, addOutputText, } from '../../lib/ResponsesParser'; -import * as Core from '../../core'; -import { APIPromise } from '../../core'; -import { APIResource } from '../../resource'; +import { ResponseStream, ResponseStreamParams } from '../../lib/responses/ResponseStream'; +import { APIResource } from '../../core/resource'; +import * as ResponsesAPI from './responses'; import * as Shared from '../shared'; import * as InputItemsAPI from './input-items'; import { InputItemListParams, InputItems, ResponseItemList } from './input-items'; -import * as ResponsesAPI from './responses'; -import { ResponseStream, ResponseStreamParams } from '../../lib/responses/ResponseStream'; -import { CursorPage } from '../../pagination'; -import { Stream } from '../../streaming'; +import { APIPromise } from '../../core/api-promise'; +import { CursorPage } from '../../core/pagination'; +import { Stream } from '../../core/streaming'; +import { buildHeaders } from '../../internal/headers'; +import { RequestOptions } from '../../internal/request-options'; +import { path } from '../../internal/utils/path'; export interface ParsedResponseOutputText extends ResponseOutputText { parsed: ParsedT | null; @@ -52,6 +54,7 @@ export interface ParsedResponse extends Response { } export type ResponseParseParams = ResponseCreateParamsNonStreaming; + export class Responses extends APIResource { inputItems: InputItemsAPI.InputItems = new InputItemsAPI.InputItems(this._client); @@ -76,18 +79,18 @@ export class Responses extends APIResource { * }); * ``` */ - create(body: ResponseCreateParamsNonStreaming, options?: Core.RequestOptions): APIPromise; + create(body: ResponseCreateParamsNonStreaming, options?: RequestOptions): APIPromise; create( body: ResponseCreateParamsStreaming, - options?: Core.RequestOptions, + options?: RequestOptions, ): APIPromise>; create( body: ResponseCreateParamsBase, - options?: Core.RequestOptions, + options?: RequestOptions, ): APIPromise | Response>; create( body: ResponseCreateParams, - options?: Core.RequestOptions, + options?: RequestOptions, ): APIPromise | APIPromise> { return ( this._client.post('/responses', { body, ...options, stream: body.stream ?? false }) as @@ -112,28 +115,27 @@ export class Responses extends APIResource { * ); * ``` */ - retrieve( - responseId: string, + responseID: string, query?: ResponseRetrieveParamsNonStreaming, - options?: Core.RequestOptions, + options?: RequestOptions, ): APIPromise; retrieve( - responseId: string, + responseID: string, query: ResponseRetrieveParamsStreaming, - options?: Core.RequestOptions, + options?: RequestOptions, ): APIPromise>; retrieve( - responseId: string, + responseID: string, query?: ResponseRetrieveParamsBase | undefined, - options?: Core.RequestOptions, + options?: RequestOptions, ): APIPromise | Response>; retrieve( - responseId: string, + responseID: string, query: ResponseRetrieveParams | undefined = {}, - options?: Core.RequestOptions, + options?: RequestOptions, ): APIPromise | APIPromise> { - return this._client.get(`/responses/${responseId}`, { + return this._client.get(path`/responses/${responseID}`, { query, ...options, stream: query?.stream ?? false, @@ -145,22 +147,22 @@ export class Responses extends APIResource { * * @example * ```ts - * await client.responses.del( + * await client.responses.delete( * 'resp_677efb5139a88190b512bc3fef8e535d', * ); * ``` */ - del(responseId: string, options?: Core.RequestOptions): Core.APIPromise { - return this._client.delete(`/responses/${responseId}`, { + delete(responseID: string, options?: RequestOptions): APIPromise { + return this._client.delete(path`/responses/${responseID}`, { ...options, - headers: { Accept: '*/*', ...options?.headers }, + headers: buildHeaders([{ Accept: '*/*' }, options?.headers]), }); } parse>( body: Params, - options?: Core.RequestOptions, - ): Core.APIPromise> { + options?: RequestOptions, + ): APIPromise> { return this._client.responses .create(body, options) ._thenUnwrap((response) => parseResponse(response as Response, body)); @@ -169,10 +171,9 @@ export class Responses extends APIResource { /** * Creates a model response stream */ - stream>( body: Params, - options?: Core.RequestOptions, + options?: RequestOptions, ): ResponseStream { return ResponseStream.createResponse(this._client, body, options); } @@ -189,16 +190,15 @@ export class Responses extends APIResource { * ); * ``` */ - - cancel(responseId: string, options?: Core.RequestOptions): Core.APIPromise { - return this._client.post(`/responses/${responseId}/cancel`, { + cancel(responseID: string, options?: RequestOptions): APIPromise { + return this._client.post(path`/responses/${responseID}/cancel`, { ...options, - headers: { Accept: '*/*', ...options?.headers }, + headers: buildHeaders([{ Accept: '*/*' }, options?.headers]), }); } } -export class ResponseItemsPage extends CursorPage {} +export type ResponseItemsPage = CursorPage; /** * A tool that controls a virtual computer. Learn more about the @@ -223,7 +223,7 @@ export interface ComputerTool { /** * The type of the computer use tool. Always `computer_use_preview`. */ - type: 'computer-preview'; + type: 'computer_use_preview'; } /** diff --git a/src/resources/uploads.ts b/src/resources/uploads.ts new file mode 100644 index 000000000..a6ab87fbe --- /dev/null +++ b/src/resources/uploads.ts @@ -0,0 +1,3 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export * from './uploads/index'; diff --git a/src/resources/uploads/parts.ts b/src/resources/uploads/parts.ts index 9b54c99e6..4e3509f9f 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 { APIResource } from '../../core/resource'; +import { APIPromise } from '../../core/api-promise'; +import { type Uploadable } from '../../core/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 9e046b48d..e4ac1752a 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 { APIResource } from '../../core/resource'; import * as FilesAPI from '../files'; import * as PartsAPI from './parts'; import { PartCreateParams, Parts, UploadPart } from './parts'; +import { APIPromise } from '../../core/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); @@ -30,15 +32,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); } /** @@ -56,12 +58,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 }); } } diff --git a/src/resources/vector-stores.ts b/src/resources/vector-stores.ts new file mode 100644 index 000000000..e7a343120 --- /dev/null +++ b/src/resources/vector-stores.ts @@ -0,0 +1,3 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export * from './vector-stores/index'; diff --git a/src/resources/vector-stores/file-batches.ts b/src/resources/vector-stores/file-batches.ts index 9be1d81a3..5b5fddeb7 100644 --- a/src/resources/vector-stores/file-batches.ts +++ b/src/resources/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 { APIResource } from '../../core/resource'; import * as FilesAPI from './files'; import { VectorStoreFilesPage } from './files'; import * as VectorStoresAPI from './vector-stores'; -import { type CursorPageParams } from '../../pagination'; +import { APIPromise } from '../../core/api-promise'; +import { CursorPage, type CursorPageParams, PagePromise } from '../../core/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( @@ -281,23 +278,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'; } @@ -306,8 +323,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/vector-stores/files.ts b/src/resources/vector-stores/files.ts index 28caf9781..d896352c8 100644 --- a/src/resources/vector-stores/files.ts +++ b/src/resources/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 { APIResource } from '../../core/resource'; import * as VectorStoresAPI from './vector-stores'; -import { CursorPage, type CursorPageParams, Page } from '../../pagination'; +import { APIPromise } from '../../core/api-promise'; +import { CursorPage, type CursorPageParams, PagePromise, Page } from '../../core/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,29 +32,26 @@ 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]), }); } /** * Update attributes on a vector store file. */ - update( - vectorStoreId: string, - fileId: string, - body: FileUpdateParams, - options?: Core.RequestOptions, - ): Core.APIPromise { - return this._client.post(`/vector_stores/${vectorStoreId}/files/${fileId}`, { + update(fileID: string, params: FileUpdateParams, options?: RequestOptions): APIPromise { + const { vector_store_id, ...body } = params; + return this._client.post(path`/vector_stores/${vector_store_id}/files/${fileID}`, { body, ...options, - headers: { 'OpenAI-Beta': 'assistants=v2', ...options?.headers }, + headers: buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), }); } @@ -58,26 +59,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]), }); } @@ -87,14 +76,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]), }); } @@ -104,12 +94,11 @@ 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); } - /** * Wait for the vector store file to finish processing. * @@ -117,19 +106,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; @@ -156,29 +152,23 @@ export class Files extends APIResource { } } } - /** * Upload a file to the `files` API and then attach it to the given vector store. * * 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); } - /** * Add a file to a vector store and poll until processing is complete. */ 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); @@ -188,24 +178,23 @@ export class Files extends APIResource { * Retrieve the parsed contents of a vector store file. */ content( - vectorStoreId: string, - fileId: string, - options?: Core.RequestOptions, - ): Core.PagePromise { + fileID: string, + params: FileContentParams, + options?: RequestOptions, + ): PagePromise { + const { vector_store_id } = params; return this._client.getAPIList( - `/vector_stores/${vectorStoreId}/files/${fileId}/content`, - FileContentResponsesPage, - { ...options, headers: { 'OpenAI-Beta': 'assistants=v2', ...options?.headers } }, + path`/vector_stores/${vector_store_id}/files/${fileID}/content`, + Page, + { ...options, headers: buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]) }, ); } } -export class VectorStoreFilesPage extends CursorPage {} +export type VectorStoreFilesPage = CursorPage; -/** - * Note: no pagination actually occurs yet, this is for forwards-compatibility. - */ -export class FileContentResponsesPage extends Page {} +// Note: no pagination actually occurs yet, this is for forwards-compatibility. +export type FileContentResponsesPage = Page; /** * A list of files attached to a vector store. @@ -330,13 +319,25 @@ 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 FileUpdateParams { /** - * 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, booleans, or numbers. + * Path param: The ID of the vector store the file belongs to. + */ + vector_store_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, booleans, or numbers. */ attributes: Record | null; } @@ -362,18 +363,32 @@ export interface FileListParams extends CursorPageParams { order?: 'asc' | 'desc'; } -Files.VectorStoreFilesPage = VectorStoreFilesPage; -Files.FileContentResponsesPage = FileContentResponsesPage; +export interface FileDeleteParams { + /** + * The ID of the vector store that the file belongs to. + */ + vector_store_id: string; +} + +export interface FileContentParams { + /** + * The ID of the vector store. + */ + vector_store_id: string; +} export declare namespace Files { export { type VectorStoreFile as VectorStoreFile, type VectorStoreFileDeleted as VectorStoreFileDeleted, type FileContentResponse as FileContentResponse, - VectorStoreFilesPage as VectorStoreFilesPage, - FileContentResponsesPage as FileContentResponsesPage, + type VectorStoreFilesPage as VectorStoreFilesPage, + type FileContentResponsesPage as FileContentResponsesPage, type FileCreateParams as FileCreateParams, + type FileRetrieveParams as FileRetrieveParams, type FileUpdateParams as FileUpdateParams, type FileListParams as FileListParams, + type FileDeleteParams as FileDeleteParams, + type FileContentParams as FileContentParams, }; } diff --git a/src/resources/vector-stores/index.ts b/src/resources/vector-stores/index.ts index 9cbcbc0b2..cbcb36221 100644 --- a/src/resources/vector-stores/index.ts +++ b/src/resources/vector-stores/index.ts @@ -4,22 +4,25 @@ export { FileBatches, type VectorStoreFileBatch, type FileBatchCreateParams, + type FileBatchRetrieveParams, + type FileBatchCancelParams, type FileBatchListFilesParams, } from './file-batches'; export { - VectorStoreFilesPage, - FileContentResponsesPage, Files, type VectorStoreFile, type VectorStoreFileDeleted, type FileContentResponse, type FileCreateParams, + type FileRetrieveParams, type FileUpdateParams, type FileListParams, + type FileDeleteParams, + type FileContentParams, + type VectorStoreFilesPage, + type FileContentResponsesPage, } from './files'; export { - VectorStoresPage, - VectorStoreSearchResponsesPage, VectorStores, type AutoFileChunkingStrategyParam, type FileChunkingStrategy, @@ -35,4 +38,6 @@ export { type VectorStoreUpdateParams, type VectorStoreListParams, type VectorStoreSearchParams, + type VectorStoresPage, + type VectorStoreSearchResponsesPage, } from './vector-stores'; diff --git a/src/resources/vector-stores/vector-stores.ts b/src/resources/vector-stores/vector-stores.ts index 7d61e7fd6..de08d0494 100644 --- a/src/resources/vector-stores/vector-stores.ts +++ b/src/resources/vector-stores/vector-stores.ts @@ -1,29 +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 { APIResource } from '../../core/resource'; 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 { + FileContentParams, FileContentResponse, FileContentResponsesPage, FileCreateParams, + FileDeleteParams, FileListParams, + FileRetrieveParams, FileUpdateParams, Files, VectorStoreFile, VectorStoreFileDeleted, VectorStoreFilesPage, } from './files'; -import { CursorPage, type CursorPageParams, Page } from '../../pagination'; +import { APIPromise } from '../../core/api-promise'; +import { CursorPage, type CursorPageParams, Page, PagePromise } from '../../core/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); @@ -32,21 +39,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]), }); } @@ -54,14 +61,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]), }); } @@ -69,31 +76,23 @@ 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]), }); } @@ -102,25 +101,27 @@ export class VectorStores extends APIResource { * filter. */ search( - vectorStoreId: string, + vectorStoreID: string, body: VectorStoreSearchParams, - options?: Core.RequestOptions, - ): Core.PagePromise { - return this._client.getAPIList(`/vector_stores/${vectorStoreId}/search`, VectorStoreSearchResponsesPage, { - body, - method: 'post', - ...options, - headers: { 'OpenAI-Beta': 'assistants=v2', ...options?.headers }, - }); + options?: RequestOptions, + ): PagePromise { + return this._client.getAPIList( + path`/vector_stores/${vectorStoreID}/search`, + Page, + { + body, + method: 'post', + ...options, + headers: buildHeaders([{ 'OpenAI-Beta': 'assistants=v2' }, options?.headers]), + }, + ); } } -export class VectorStoresPage extends CursorPage {} +export type VectorStoresPage = CursorPage; -/** - * Note: no pagination actually occurs yet, this is for forwards-compatibility. - */ -export class VectorStoreSearchResponsesPage extends Page {} +// Note: no pagination actually occurs yet, this is for forwards-compatibility. +export type VectorStoreSearchResponsesPage = Page; /** * The default strategy. This strategy currently uses a `max_chunk_size_tokens` of @@ -503,11 +504,7 @@ export namespace VectorStoreSearchParams { } } -VectorStores.VectorStoresPage = VectorStoresPage; -VectorStores.VectorStoreSearchResponsesPage = VectorStoreSearchResponsesPage; VectorStores.Files = Files; -VectorStores.VectorStoreFilesPage = VectorStoreFilesPage; -VectorStores.FileContentResponsesPage = FileContentResponsesPage; VectorStores.FileBatches = FileBatches; export declare namespace VectorStores { @@ -522,8 +519,8 @@ export declare namespace VectorStores { type VectorStore as VectorStore, type VectorStoreDeleted as VectorStoreDeleted, type VectorStoreSearchResponse as VectorStoreSearchResponse, - VectorStoresPage as VectorStoresPage, - VectorStoreSearchResponsesPage as VectorStoreSearchResponsesPage, + type VectorStoresPage as VectorStoresPage, + type VectorStoreSearchResponsesPage as VectorStoreSearchResponsesPage, type VectorStoreCreateParams as VectorStoreCreateParams, type VectorStoreUpdateParams as VectorStoreUpdateParams, type VectorStoreListParams as VectorStoreListParams, @@ -535,17 +532,22 @@ export declare namespace VectorStores { type VectorStoreFile as VectorStoreFile, type VectorStoreFileDeleted as VectorStoreFileDeleted, type FileContentResponse as FileContentResponse, - VectorStoreFilesPage as VectorStoreFilesPage, - FileContentResponsesPage as FileContentResponsesPage, + type VectorStoreFilesPage as VectorStoreFilesPage, + type FileContentResponsesPage as FileContentResponsesPage, type FileCreateParams as FileCreateParams, + type FileRetrieveParams as FileRetrieveParams, type FileUpdateParams as FileUpdateParams, type FileListParams as FileListParams, + type FileDeleteParams as FileDeleteParams, + type FileContentParams as FileContentParams, }; 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/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 ee25daca6..9e6da1063 100644 --- a/src/streaming.ts +++ b/src/streaming.ts @@ -1,329 +1,2 @@ -import { ReadableStream, type Response } from './_shims/index'; -import { OpenAIError } from './error'; -import { findDoubleNewlineIndex, LineDecoder } from './internal/decoders/line'; -import { ReadableStreamToAsyncIterable } from './internal/stream-utils'; - -import { createResponseHeaders } from './core'; -import { APIError } from './error'; - -type Bytes = string | ArrayBuffer | Uint8Array | Buffer | null | undefined; - -export type ServerSentEvent = { - event: string | null; - data: string; - raw: string[]; -}; - -export class Stream implements AsyncIterable { - controller: AbortController; - - constructor( - private iterator: () => AsyncIterator, - controller: AbortController, - ) { - this.controller = controller; - } - - static fromSSEResponse(response: Response, controller: AbortController): Stream { - let consumed = false; - - async function* iterator(): AsyncIterator { - if (consumed) { - throw new Error('Cannot iterate over a consumed stream, use `.tee()` to split the stream.'); - } - consumed = true; - let done = false; - try { - for await (const sse of _iterSSEMessages(response, controller)) { - if (done) continue; - - if (sse.data.startsWith('[DONE]')) { - done = true; - continue; - } - - if ( - sse.event === null || - sse.event.startsWith('response.') || - sse.event.startsWith('transcript.') - ) { - let data; - - try { - data = JSON.parse(sse.data); - } catch (e) { - console.error(`Could not parse message into JSON:`, sse.data); - console.error(`From chunk:`, sse.raw); - throw e; - } - - if (data && data.error) { - throw new APIError(undefined, data.error, undefined, createResponseHeaders(response.headers)); - } - - yield data; - } else { - let data; - try { - data = JSON.parse(sse.data); - } catch (e) { - console.error(`Could not parse message into JSON:`, sse.data); - console.error(`From chunk:`, sse.raw); - throw e; - } - // TODO: Is this where the error should be thrown? - if (sse.event == 'error') { - throw new APIError(undefined, data.error, data.message, undefined); - } - yield { event: sse.event, data: data } as any; - } - } - done = true; - } catch (e) { - // If the user calls `stream.controller.abort()`, we should exit without throwing. - if (e instanceof Error && e.name === 'AbortError') return; - throw e; - } finally { - // If the user `break`s, abort the ongoing request. - if (!done) controller.abort(); - } - } - - return new Stream(iterator, controller); - } - - /** - * Generates a Stream from a newline-separated ReadableStream - * where each item is a JSON value. - */ - static fromReadableStream(readableStream: ReadableStream, controller: AbortController): Stream { - let consumed = false; - - async function* iterLines(): AsyncGenerator { - const lineDecoder = new LineDecoder(); - - const iter = ReadableStreamToAsyncIterable(readableStream); - for await (const chunk of iter) { - for (const line of lineDecoder.decode(chunk)) { - yield line; - } - } - - for (const line of lineDecoder.flush()) { - yield line; - } - } - - async function* iterator(): AsyncIterator { - if (consumed) { - throw new Error('Cannot iterate over a consumed stream, use `.tee()` to split the stream.'); - } - consumed = true; - let done = false; - try { - for await (const line of iterLines()) { - if (done) continue; - if (line) yield JSON.parse(line); - } - done = true; - } catch (e) { - // If the user calls `stream.controller.abort()`, we should exit without throwing. - if (e instanceof Error && e.name === 'AbortError') return; - throw e; - } finally { - // If the user `break`s, abort the ongoing request. - if (!done) controller.abort(); - } - } - - return new Stream(iterator, controller); - } - - [Symbol.asyncIterator](): AsyncIterator { - return this.iterator(); - } - - /** - * Splits the stream into two streams which can be - * independently read from at different speeds. - */ - tee(): [Stream, Stream] { - const left: Array>> = []; - const right: Array>> = []; - const iterator = this.iterator(); - - const teeIterator = (queue: Array>>): AsyncIterator => { - return { - next: () => { - if (queue.length === 0) { - const result = iterator.next(); - left.push(result); - right.push(result); - } - return queue.shift()!; - }, - }; - }; - - return [ - new Stream(() => teeIterator(left), this.controller), - new Stream(() => teeIterator(right), this.controller), - ]; - } - - /** - * Converts this stream to a newline-separated ReadableStream of - * JSON stringified values in the stream - * which can be turned back into a Stream with `Stream.fromReadableStream()`. - */ - toReadableStream(): ReadableStream { - const self = this; - let iter: AsyncIterator; - const encoder = new TextEncoder(); - - return new ReadableStream({ - async start() { - iter = self[Symbol.asyncIterator](); - }, - async pull(ctrl: any) { - try { - const { value, done } = await iter.next(); - if (done) return ctrl.close(); - - const bytes = encoder.encode(JSON.stringify(value) + '\n'); - - ctrl.enqueue(bytes); - } catch (err) { - ctrl.error(err); - } - }, - async cancel() { - await iter.return?.(); - }, - }); - } -} - -export async function* _iterSSEMessages( - response: Response, - controller: AbortController, -): AsyncGenerator { - if (!response.body) { - controller.abort(); - throw new OpenAIError(`Attempted to iterate over a response with no body`); - } - - const sseDecoder = new SSEDecoder(); - const lineDecoder = new LineDecoder(); - - const iter = ReadableStreamToAsyncIterable(response.body); - for await (const sseChunk of iterSSEChunks(iter)) { - for (const line of lineDecoder.decode(sseChunk)) { - const sse = sseDecoder.decode(line); - if (sse) yield sse; - } - } - - for (const line of lineDecoder.flush()) { - const sse = sseDecoder.decode(line); - if (sse) yield sse; - } -} - -/** - * Given an async iterable iterator, iterates over it and yields full - * SSE chunks, i.e. yields when a double new-line is encountered. - */ -async function* iterSSEChunks(iterator: AsyncIterableIterator): AsyncGenerator { - let data = new Uint8Array(); - - for await (const chunk of iterator) { - if (chunk == null) { - continue; - } - - const binaryChunk = - chunk instanceof ArrayBuffer ? new Uint8Array(chunk) - : typeof chunk === 'string' ? new TextEncoder().encode(chunk) - : chunk; - - let newData = new Uint8Array(data.length + binaryChunk.length); - newData.set(data); - newData.set(binaryChunk, data.length); - data = newData; - - let patternIndex; - while ((patternIndex = findDoubleNewlineIndex(data)) !== -1) { - yield data.slice(0, patternIndex); - data = data.slice(patternIndex); - } - } - - if (data.length > 0) { - yield data; - } -} - -class SSEDecoder { - private data: string[]; - private event: string | null; - private chunks: string[]; - - constructor() { - this.event = null; - this.data = []; - this.chunks = []; - } - - decode(line: string) { - if (line.endsWith('\r')) { - line = line.substring(0, line.length - 1); - } - - if (!line) { - // empty line and we didn't previously encounter any messages - if (!this.event && !this.data.length) return null; - - const sse: ServerSentEvent = { - event: this.event, - data: this.data.join('\n'), - raw: this.chunks, - }; - - this.event = null; - this.data = []; - this.chunks = []; - - return sse; - } - - this.chunks.push(line); - - if (line.startsWith(':')) { - return null; - } - - let [fieldname, _, value] = partition(line, ':'); - - if (value.startsWith(' ')) { - value = value.substring(1); - } - - if (fieldname === 'event') { - this.event = value; - } else if (fieldname === 'data') { - this.data.push(value); - } - - return null; - } -} - -function partition(str: string, delimiter: string): [string, string, string] { - const index = str.indexOf(delimiter); - if (index !== -1) { - return [str.substring(0, index), delimiter, str.substring(index + delimiter.length)]; - } - - return [str, '', '']; -} +/** @deprecated Import from ./core/streaming instead */ +export * from './core/streaming'; diff --git a/src/uploads.ts b/src/uploads.ts index 8fd2154d4..b2ef64710 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`, - ); - } -}; +/** @deprecated Import from ./core/uploads instead */ +export * from './core/uploads'; diff --git a/src/version.ts b/src/version.ts index 42c4cab74..e156b0eaa 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1 +1 @@ -export const VERSION = '4.104.0'; // x-release-please-version +export const VERSION = '5.0.0'; // x-release-please-version diff --git a/tests/api-resources/audio/transcriptions.test.ts b/tests/api-resources/audio/transcriptions.test.ts index ad76808d0..4111b519f 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 7c7397d06..c895f0809 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 16bc9f942..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', @@ -55,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(); @@ -84,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( @@ -101,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; @@ -111,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 index dbb92ead3..1a75a532c 100644 --- a/tests/api-resources/beta/realtime/sessions.test.ts +++ b/tests/api-resources/beta/realtime/sessions.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/beta/realtime/transcription-sessions.test.ts b/tests/api-resources/beta/realtime/transcription-sessions.test.ts index d52ce2403..2c7cbbb15 100644 --- a/tests/api-resources/beta/realtime/transcription-sessions.test.ts +++ b/tests/api-resources/beta/realtime/transcription-sessions.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/beta/threads/messages.test.ts b/tests/api-resources/beta/threads/messages.test.ts index e125edd84..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', @@ -32,8 +31,8 @@ describe('resource messages', () => { }); }); - 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 4b2b8030b..becea1425 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', @@ -50,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; @@ -61,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; @@ -79,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(); @@ -90,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( @@ -108,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; @@ -119,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(); @@ -140,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 bc92a0c8a..342e673b3 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( @@ -67,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(); @@ -85,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; @@ -96,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(); diff --git a/tests/api-resources/chat/completions/completions.test.ts b/tests/api-resources/chat/completions/completions.test.ts index 60c23591a..b593ab4eb 100644 --- a/tests/api-resources/chat/completions/completions.test.ts +++ b/tests/api-resources/chat/completions/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', @@ -81,13 +80,6 @@ describe('resource completions', () => { 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.chat.completions.retrieve('completion_id', { path: '/_stainless_unknown_path' }), - ).rejects.toThrow(OpenAI.NotFoundError); - }); - test('update: only required params', async () => { const responsePromise = client.chat.completions.update('completion_id', { metadata: { foo: 'string' } }); const rawResponse = await responsePromise.asResponse(); @@ -114,13 +106,6 @@ describe('resource completions', () => { 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.chat.completions.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( @@ -131,8 +116,8 @@ describe('resource completions', () => { ).rejects.toThrow(OpenAI.NotFoundError); }); - test('del', async () => { - const responsePromise = client.chat.completions.del('completion_id'); + test('delete', async () => { + const responsePromise = client.chat.completions.delete('completion_id'); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -141,11 +126,4 @@ describe('resource completions', () => { 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.chat.completions.del('completion_id', { path: '/_stainless_unknown_path' }), - ).rejects.toThrow(OpenAI.NotFoundError); - }); }); diff --git a/tests/api-resources/chat/completions/messages.test.ts b/tests/api-resources/chat/completions/messages.test.ts index 664106cb9..98dd22167 100644 --- a/tests/api-resources/chat/completions/messages.test.ts +++ b/tests/api-resources/chat/completions/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', @@ -20,13 +19,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.chat.completions.messages.list('completion_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( diff --git a/tests/api-resources/completions.test.ts b/tests/api-resources/completions.test.ts index c98501a87..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', diff --git a/tests/api-resources/containers/containers.test.ts b/tests/api-resources/containers/containers.test.ts index 11c6f166c..aa8bd8211 100644 --- a/tests/api-resources/containers/containers.test.ts +++ b/tests/api-resources/containers/containers.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', @@ -39,13 +38,6 @@ describe('resource containers', () => { 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.containers.retrieve('container_id', { path: '/_stainless_unknown_path' }), - ).rejects.toThrow(OpenAI.NotFoundError); - }); - test('list', async () => { const responsePromise = client.containers.list(); const rawResponse = await responsePromise.asResponse(); @@ -57,13 +49,6 @@ describe('resource containers', () => { 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.containers.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( @@ -74,8 +59,8 @@ describe('resource containers', () => { ).rejects.toThrow(OpenAI.NotFoundError); }); - test('del', async () => { - const responsePromise = client.containers.del('container_id'); + test('delete', async () => { + const responsePromise = client.containers.delete('container_id'); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -84,11 +69,4 @@ describe('resource containers', () => { 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.containers.del('container_id', { path: '/_stainless_unknown_path' })).rejects.toThrow( - OpenAI.NotFoundError, - ); - }); }); diff --git a/tests/api-resources/containers/files/content.test.ts b/tests/api-resources/containers/files/content.test.ts index c4b10fdf4..1792ed49a 100644 --- a/tests/api-resources/containers/files/content.test.ts +++ b/tests/api-resources/containers/files/content.test.ts @@ -8,12 +8,9 @@ const client = new OpenAI({ }); describe('resource content', () => { - 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.containers.files.content.retrieve('container_id', 'file_id', { - path: '/_stainless_unknown_path', - }), - ).rejects.toThrow(OpenAI.NotFoundError); + test('retrieve: required and optional params', async () => { + const response = await client.containers.files.content.retrieve('file_id', { + container_id: 'container_id', + }); }); }); diff --git a/tests/api-resources/containers/files/files.test.ts b/tests/api-resources/containers/files/files.test.ts index 79f47e9ad..f57b46316 100644 --- a/tests/api-resources/containers/files/files.test.ts +++ b/tests/api-resources/containers/files/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', @@ -20,8 +19,8 @@ describe('resource files', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - test('retrieve', async () => { - const responsePromise = client.containers.files.retrieve('container_id', 'file_id'); + test('retrieve: only required params', async () => { + const responsePromise = client.containers.files.retrieve('file_id', { container_id: 'container_id' }); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -31,11 +30,8 @@ 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.containers.files.retrieve('container_id', 'file_id', { path: '/_stainless_unknown_path' }), - ).rejects.toThrow(OpenAI.NotFoundError); + test('retrieve: required and optional params', async () => { + const response = await client.containers.files.retrieve('file_id', { container_id: 'container_id' }); }); test('list', async () => { @@ -49,13 +45,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.containers.files.list('container_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( @@ -67,8 +56,8 @@ describe('resource files', () => { ).rejects.toThrow(OpenAI.NotFoundError); }); - test('del', async () => { - const responsePromise = client.containers.files.del('container_id', 'file_id'); + test('delete: only required params', async () => { + const responsePromise = client.containers.files.delete('file_id', { container_id: 'container_id' }); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -78,10 +67,7 @@ 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.containers.files.del('container_id', 'file_id', { path: '/_stainless_unknown_path' }), - ).rejects.toThrow(OpenAI.NotFoundError); + test('delete: required and optional params', async () => { + const response = await client.containers.files.delete('file_id', { container_id: 'container_id' }); }); }); diff --git a/tests/api-resources/embeddings.test.ts b/tests/api-resources/embeddings.test.ts index 629265643..2ba17dbf1 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'; import { mockFetch } from '../utils/mock-fetch'; import fs from 'fs/promises'; import Path from 'path'; @@ -43,7 +42,7 @@ describe('resource embeddings', () => { model: 'text-embedding-3-small', }); - expect(response.data?.at(0)?.embedding).toBeInstanceOf(Array); + expect(Array.isArray(response.data?.at(0)?.embedding)).toBe(true); expect(response.data?.at(0)?.embedding.at(0)).toBe(-0.09928705543279648); }); @@ -55,7 +54,7 @@ describe('resource embeddings', () => { encoding_format: 'float', }); - expect(response.data?.at(0)?.embedding).toBeInstanceOf(Array); + expect(Array.isArray(response.data?.at(0)?.embedding)).toBe(true); expect(response.data?.at(0)?.embedding.at(0)).toBe(-0.099287055); }); diff --git a/tests/api-resources/evals/evals.test.ts b/tests/api-resources/evals/evals.test.ts index 45d1c4f9b..a852ef8f7 100644 --- a/tests/api-resources/evals/evals.test.ts +++ b/tests/api-resources/evals/evals.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', @@ -61,13 +60,6 @@ describe('resource evals', () => { 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.evals.retrieve('eval_id', { path: '/_stainless_unknown_path' })).rejects.toThrow( - OpenAI.NotFoundError, - ); - }); - test('update', async () => { const responsePromise = client.evals.update('eval_id', {}); const rawResponse = await responsePromise.asResponse(); @@ -90,13 +82,6 @@ describe('resource evals', () => { 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.evals.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( @@ -107,8 +92,8 @@ describe('resource evals', () => { ).rejects.toThrow(OpenAI.NotFoundError); }); - test('del', async () => { - const responsePromise = client.evals.del('eval_id'); + test('delete', async () => { + const responsePromise = client.evals.delete('eval_id'); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -117,11 +102,4 @@ describe('resource evals', () => { 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.evals.del('eval_id', { path: '/_stainless_unknown_path' })).rejects.toThrow( - OpenAI.NotFoundError, - ); - }); }); diff --git a/tests/api-resources/evals/runs/output-items.test.ts b/tests/api-resources/evals/runs/output-items.test.ts index ff075b404..e173b2a28 100644 --- a/tests/api-resources/evals/runs/output-items.test.ts +++ b/tests/api-resources/evals/runs/output-items.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 outputItems', () => { - test('retrieve', async () => { - const responsePromise = client.evals.runs.outputItems.retrieve('eval_id', 'run_id', 'output_item_id'); + test('retrieve: only required params', async () => { + const responsePromise = client.evals.runs.outputItems.retrieve('output_item_id', { + eval_id: 'eval_id', + run_id: 'run_id', + }); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -20,17 +22,15 @@ describe('resource outputItems', () => { 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.evals.runs.outputItems.retrieve('eval_id', 'run_id', 'output_item_id', { - path: '/_stainless_unknown_path', - }), - ).rejects.toThrow(OpenAI.NotFoundError); + test('retrieve: required and optional params', async () => { + const response = await client.evals.runs.outputItems.retrieve('output_item_id', { + eval_id: 'eval_id', + run_id: 'run_id', + }); }); - test('list', async () => { - const responsePromise = client.evals.runs.outputItems.list('eval_id', 'run_id'); + test('list: only required params', async () => { + const responsePromise = client.evals.runs.outputItems.list('run_id', { eval_id: 'eval_id' }); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -40,22 +40,13 @@ describe('resource outputItems', () => { 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.evals.runs.outputItems.list('eval_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.evals.runs.outputItems.list( - 'eval_id', - 'run_id', - { after: 'after', limit: 0, order: 'asc', status: 'fail' }, - { path: '/_stainless_unknown_path' }, - ), - ).rejects.toThrow(OpenAI.NotFoundError); + test('list: required and optional params', async () => { + const response = await client.evals.runs.outputItems.list('run_id', { + eval_id: 'eval_id', + after: 'after', + limit: 0, + order: 'asc', + status: 'fail', + }); }); }); diff --git a/tests/api-resources/evals/runs/runs.test.ts b/tests/api-resources/evals/runs/runs.test.ts index 786df0ba1..d17cd2a9a 100644 --- a/tests/api-resources/evals/runs/runs.test.ts +++ b/tests/api-resources/evals/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', @@ -33,8 +32,8 @@ describe('resource runs', () => { }); }); - test('retrieve', async () => { - const responsePromise = client.evals.runs.retrieve('eval_id', 'run_id'); + test('retrieve: only required params', async () => { + const responsePromise = client.evals.runs.retrieve('run_id', { eval_id: 'eval_id' }); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -44,11 +43,8 @@ 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.evals.runs.retrieve('eval_id', 'run_id', { path: '/_stainless_unknown_path' }), - ).rejects.toThrow(OpenAI.NotFoundError); + test('retrieve: required and optional params', async () => { + const response = await client.evals.runs.retrieve('run_id', { eval_id: 'eval_id' }); }); test('list', async () => { @@ -62,13 +58,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.evals.runs.list('eval_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( @@ -80,8 +69,8 @@ describe('resource runs', () => { ).rejects.toThrow(OpenAI.NotFoundError); }); - test('del', async () => { - const responsePromise = client.evals.runs.del('eval_id', 'run_id'); + test('delete: only required params', async () => { + const responsePromise = client.evals.runs.delete('run_id', { eval_id: 'eval_id' }); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -91,15 +80,12 @@ describe('resource runs', () => { 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.evals.runs.del('eval_id', 'run_id', { path: '/_stainless_unknown_path' }), - ).rejects.toThrow(OpenAI.NotFoundError); + test('delete: required and optional params', async () => { + const response = await client.evals.runs.delete('run_id', { eval_id: 'eval_id' }); }); - test('cancel', async () => { - const responsePromise = client.evals.runs.cancel('eval_id', 'run_id'); + test('cancel: only required params', async () => { + const responsePromise = client.evals.runs.cancel('run_id', { eval_id: 'eval_id' }); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -109,10 +95,7 @@ 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.evals.runs.cancel('eval_id', 'run_id', { path: '/_stainless_unknown_path' }), - ).rejects.toThrow(OpenAI.NotFoundError); + test('cancel: required and optional params', async () => { + const response = await client.evals.runs.cancel('run_id', { eval_id: 'eval_id' }); }); }); 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/alpha/graders.test.ts b/tests/api-resources/fine-tuning/alpha/graders.test.ts index 8e47a4c42..a34373e85 100644 --- a/tests/api-resources/fine-tuning/alpha/graders.test.ts +++ b/tests/api-resources/fine-tuning/alpha/graders.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/fine-tuning/checkpoints/permissions.test.ts b/tests/api-resources/fine-tuning/checkpoints/permissions.test.ts index 1e4b40a94..8427ee957 100644 --- a/tests/api-resources/fine-tuning/checkpoints/permissions.test.ts +++ b/tests/api-resources/fine-tuning/checkpoints/permissions.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', @@ -41,15 +40,6 @@ describe('resource permissions', () => { 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.checkpoints.permissions.retrieve('ft-AF1WoRqd3aJAHsqc9NY7iL8F', { - path: '/_stainless_unknown_path', - }), - ).rejects.toThrow(OpenAI.NotFoundError); - }); - 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( @@ -61,11 +51,10 @@ describe('resource permissions', () => { ).rejects.toThrow(OpenAI.NotFoundError); }); - test('del', async () => { - const responsePromise = client.fineTuning.checkpoints.permissions.del( - 'ft:gpt-4o-mini-2024-07-18:org:weather:B7R9VjQd', - 'cp_zc4Q7MP6XxulcVzj4MZdwsAB', - ); + test('delete: only required params', async () => { + const responsePromise = client.fineTuning.checkpoints.permissions.delete('cp_zc4Q7MP6XxulcVzj4MZdwsAB', { + fine_tuned_model_checkpoint: 'ft:gpt-4o-mini-2024-07-18:org:weather:B7R9VjQd', + }); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -75,14 +64,9 @@ describe('resource permissions', () => { 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.fineTuning.checkpoints.permissions.del( - 'ft:gpt-4o-mini-2024-07-18:org:weather:B7R9VjQd', - 'cp_zc4Q7MP6XxulcVzj4MZdwsAB', - { path: '/_stainless_unknown_path' }, - ), - ).rejects.toThrow(OpenAI.NotFoundError); + test('delete: required and optional params', async () => { + const response = await client.fineTuning.checkpoints.permissions.delete('cp_zc4Q7MP6XxulcVzj4MZdwsAB', { + fine_tuned_model_checkpoint: 'ft:gpt-4o-mini-2024-07-18:org:weather:B7R9VjQd', + }); }); }); 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 fe8c9efee..8cd4088ab 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', @@ -34,6 +33,7 @@ describe('resource jobs', () => { wandb: { project: 'my-wandb-project', entity: 'entity', name: 'name', tags: ['custom-tag'] }, }, ], + metadata: { foo: 'string' }, method: { type: 'supervised', dpo: { @@ -83,13 +83,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(); @@ -101,17 +94,13 @@ 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( - client.fineTuning.jobs.list({ after: 'after', limit: 0 }, { path: '/_stainless_unknown_path' }), + client.fineTuning.jobs.list( + { after: 'after', limit: 0, metadata: { foo: 'string' } }, + { path: '/_stainless_unknown_path' }, + ), ).rejects.toThrow(OpenAI.NotFoundError); }); @@ -126,13 +115,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(); @@ -144,13 +126,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( @@ -173,13 +148,6 @@ describe('resource jobs', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - test('pause: 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.pause('ft-AF1WoRqd3aJAHsqc9NY7iL8F', { path: '/_stainless_unknown_path' }), - ).rejects.toThrow(OpenAI.NotFoundError); - }); - test('resume', async () => { const responsePromise = client.fineTuning.jobs.resume('ft-AF1WoRqd3aJAHsqc9NY7iL8F'); const rawResponse = await responsePromise.asResponse(); @@ -190,11 +158,4 @@ describe('resource jobs', () => { expect(dataAndResponse.data).toBe(response); expect(dataAndResponse.response).toBe(rawResponse); }); - - test('resume: 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.resume('ft-AF1WoRqd3aJAHsqc9NY7iL8F', { path: '/_stainless_unknown_path' }), - ).rejects.toThrow(OpenAI.NotFoundError); - }); }); diff --git a/tests/api-resources/images.test.ts b/tests/api-resources/images.test.ts index 04fca0a2a..ba62d993c 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 107ce9974..c3dce6843 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/responses/input-items.test.ts b/tests/api-resources/responses/input-items.test.ts index 25ab166c0..a96128939 100644 --- a/tests/api-resources/responses/input-items.test.ts +++ b/tests/api-resources/responses/input-items.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 inputItems', () => { 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.responses.inputItems.list('response_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( diff --git a/tests/api-resources/responses/responses.test.ts b/tests/api-resources/responses/responses.test.ts index 97847b28a..f1480f8c3 100644 --- a/tests/api-resources/responses/responses.test.ts +++ b/tests/api-resources/responses/responses.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', @@ -75,8 +74,8 @@ describe('resource responses', () => { ).rejects.toThrow(OpenAI.NotFoundError); }); - test('del', async () => { - const responsePromise = client.responses.del('resp_677efb5139a88190b512bc3fef8e535d'); + test('delete', async () => { + const responsePromise = client.responses.delete('resp_677efb5139a88190b512bc3fef8e535d'); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -86,13 +85,6 @@ describe('resource responses', () => { 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.responses.del('resp_677efb5139a88190b512bc3fef8e535d', { path: '/_stainless_unknown_path' }), - ).rejects.toThrow(OpenAI.NotFoundError); - }); - test('cancel', async () => { const responsePromise = client.responses.cancel('resp_677efb5139a88190b512bc3fef8e535d'); const rawResponse = await responsePromise.asResponse(); @@ -103,11 +95,4 @@ describe('resource responses', () => { 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.responses.cancel('resp_677efb5139a88190b512bc3fef8e535d', { path: '/_stainless_unknown_path' }), - ).rejects.toThrow(OpenAI.NotFoundError); - }); }); 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/api-resources/vector-stores/file-batches.test.ts b/tests/api-resources/vector-stores/file-batches.test.ts index c0447a838..e765a2ace 100644 --- a/tests/api-resources/vector-stores/file-batches.test.ts +++ b/tests/api-resources/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', @@ -28,8 +27,10 @@ describe('resource fileBatches', () => { }); }); - test('retrieve', async () => { - const responsePromise = client.vectorStores.fileBatches.retrieve('vs_abc123', 'vsfb_abc123'); + test('retrieve: only required params', async () => { + const responsePromise = client.vectorStores.fileBatches.retrieve('vsfb_abc123', { + vector_store_id: 'vs_abc123', + }); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -39,17 +40,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.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.vectorStores.fileBatches.retrieve('vsfb_abc123', { + vector_store_id: 'vs_abc123', + }); }); - test('cancel', async () => { - const responsePromise = client.vectorStores.fileBatches.cancel('vector_store_id', 'batch_id'); + test('cancel: only required params', async () => { + const responsePromise = client.vectorStores.fileBatches.cancel('batch_id', { + vector_store_id: 'vector_store_id', + }); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -59,17 +59,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.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.vectorStores.fileBatches.cancel('batch_id', { + vector_store_id: 'vector_store_id', + }); }); - test('listFiles', async () => { - const responsePromise = client.vectorStores.fileBatches.listFiles('vector_store_id', 'batch_id'); + test('listFiles: only required params', async () => { + const responsePromise = client.vectorStores.fileBatches.listFiles('batch_id', { + vector_store_id: 'vector_store_id', + }); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -79,24 +78,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.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.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.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/vector-stores/files.test.ts b/tests/api-resources/vector-stores/files.test.ts index 86a8f9bb4..9e9afc95d 100644 --- a/tests/api-resources/vector-stores/files.test.ts +++ b/tests/api-resources/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', @@ -28,8 +27,10 @@ describe('resource files', () => { }); }); - test('retrieve', async () => { - const responsePromise = client.vectorStores.files.retrieve('vs_abc123', 'file-abc123'); + test('retrieve: only required params', async () => { + const responsePromise = client.vectorStores.files.retrieve('file-abc123', { + vector_store_id: 'vs_abc123', + }); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -39,15 +40,15 @@ 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.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.vectorStores.files.retrieve('file-abc123', { + vector_store_id: 'vs_abc123', + }); }); test('update: only required params', async () => { - const responsePromise = client.vectorStores.files.update('vs_abc123', 'file-abc123', { + const responsePromise = client.vectorStores.files.update('file-abc123', { + vector_store_id: 'vs_abc123', attributes: { foo: 'string' }, }); const rawResponse = await responsePromise.asResponse(); @@ -60,7 +61,8 @@ describe('resource files', () => { }); test('update: required and optional params', async () => { - const response = await client.vectorStores.files.update('vs_abc123', 'file-abc123', { + const response = await client.vectorStores.files.update('file-abc123', { + vector_store_id: 'vs_abc123', attributes: { foo: 'string' }, }); }); @@ -76,13 +78,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.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( @@ -94,8 +89,10 @@ describe('resource files', () => { ).rejects.toThrow(OpenAI.NotFoundError); }); - test('del', async () => { - const responsePromise = client.vectorStores.files.del('vector_store_id', 'file_id'); + test('delete: only required params', async () => { + const responsePromise = client.vectorStores.files.delete('file_id', { + vector_store_id: 'vector_store_id', + }); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -105,15 +102,16 @@ 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.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.vectorStores.files.delete('file_id', { + vector_store_id: 'vector_store_id', + }); }); - test('content', async () => { - const responsePromise = client.vectorStores.files.content('vs_abc123', 'file-abc123'); + test('content: only required params', async () => { + const responsePromise = client.vectorStores.files.content('file-abc123', { + vector_store_id: 'vs_abc123', + }); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -123,10 +121,7 @@ describe('resource files', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - 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.vectorStores.files.content('vs_abc123', 'file-abc123', { path: '/_stainless_unknown_path' }), - ).rejects.toThrow(OpenAI.NotFoundError); + test('content: required and optional params', async () => { + const response = await client.vectorStores.files.content('file-abc123', { vector_store_id: 'vs_abc123' }); }); }); diff --git a/tests/api-resources/vector-stores/vector-stores.test.ts b/tests/api-resources/vector-stores/vector-stores.test.ts index 465904a00..830397279 100644 --- a/tests/api-resources/vector-stores/vector-stores.test.ts +++ b/tests/api-resources/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.vectorStores.retrieve('vector_store_id', { path: '/_stainless_unknown_path' }), - ).rejects.toThrow(OpenAI.NotFoundError); - }); - test('update', async () => { const responsePromise = client.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.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.vectorStores.del('vector_store_id'); + test('delete', async () => { + const responsePromise = client.vectorStores.delete('vector_store_id'); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -88,13 +73,6 @@ describe('resource vectorStores', () => { 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.vectorStores.del('vector_store_id', { path: '/_stainless_unknown_path' }), - ).rejects.toThrow(OpenAI.NotFoundError); - }); - test('search: only required params', async () => { const responsePromise = client.vectorStores.search('vs_abc123', { query: '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..08cae4da0 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/core/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/helpers/zod.test.ts b/tests/helpers/zod.test.ts index 02d8a7a8f..2eb8909a8 100644 --- a/tests/helpers/zod.test.ts +++ b/tests/helpers/zod.test.ts @@ -51,7 +51,7 @@ describe('zodResponseFormat', () => { z.object({ city: z.string(), temperature: z.number(), - units: z.enum(['c', 'f']).optional(), + units: z.enum(['c', 'f']).optional().nullable(), }), 'location', ).json_schema, @@ -69,11 +69,25 @@ describe('zodResponseFormat', () => { "type": "number", }, "units": { - "enum": [ - "c", - "f", + "anyOf": [ + { + "anyOf": [ + { + "not": {}, + }, + { + "enum": [ + "c", + "f", + ], + "type": "string", + }, + ], + }, + { + "type": "null", + }, ], - "type": "string", }, }, "required": [ @@ -279,42 +293,32 @@ describe('zodResponseFormat', () => { `); }); - it('warns on optional fields', () => { - const consoleSpy = jest.spyOn(console, 'warn'); - consoleSpy.mockClear(); - - zodResponseFormat( - z.object({ - required: z.string(), - optional: z.string().optional(), - optional_and_nullable: z.string().optional().nullable(), - }), - 'schema', - ); - - expect(consoleSpy).toHaveBeenCalledWith( - 'Zod field at `#/definitions/schema/properties/optional` uses `.optional()` without `.nullable()` which is not supported by the API. See: https://platform.openai.com/docs/guides/structured-outputs?api-mode=responses#all-fields-must-be-required\nThis will become an error in a future version of the SDK.', + it('throws error on optional fields', () => { + expect(() => + zodResponseFormat( + z.object({ + required: z.string(), + optional: z.string().optional(), + optional_and_nullable: z.string().optional().nullable(), + }), + 'schema', + ), + ).toThrowErrorMatchingInlineSnapshot( + `"Zod field at \`#/definitions/schema/properties/optional\` uses \`.optional()\` without \`.nullable()\` which is not supported by the API. See: https://platform.openai.com/docs/guides/structured-outputs?api-mode=responses#all-fields-must-be-required"`, ); - expect(consoleSpy).toHaveBeenCalledTimes(1); }); - it('warns on nested optional fields', () => { - const consoleSpy = jest.spyOn(console, 'warn'); - consoleSpy.mockClear(); - - zodResponseFormat( - z.object({ - foo: z.object({ bar: z.array(z.object({ can_be_missing: z.boolean().optional() })) }), - }), - 'schema', - ); - - expect(consoleSpy).toHaveBeenCalledWith( - expect.stringContaining( - 'Zod field at `#/definitions/schema/properties/foo/properties/bar/items/properties/can_be_missing` uses `.optional()`', + it('throws error on nested optional fields', () => { + expect(() => + zodResponseFormat( + z.object({ + foo: z.object({ bar: z.array(z.object({ can_be_missing: z.boolean().optional() })) }), + }), + 'schema', ), + ).toThrowErrorMatchingInlineSnapshot( + `"Zod field at \`#/definitions/schema/properties/foo/properties/bar/items/properties/can_be_missing\` uses \`.optional()\` without \`.nullable()\` which is not supported by the API. See: https://platform.openai.com/docs/guides/structured-outputs?api-mode=responses#all-fields-must-be-required"`, ); - expect(consoleSpy).toHaveBeenCalledTimes(1); }); it('does not warn on union nullable fields', () => { diff --git a/tests/index.test.ts b/tests/index.test.ts index 6227d6fbe..401cc5c6e 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/core/api-promise'; + +import util from 'node:util'; import OpenAI from 'openai'; import { APIUserAbortError } from 'openai'; -import { debug, 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(); }); }); @@ -133,7 +262,7 @@ describe('instantiate client', () => { test('normalized method', async () => { let capturedRequest: RequestInit | undefined; - const testFetch = async (url: RequestInfo, init: RequestInit = {}): Promise => { + const testFetch = async (url: string | URL | Request, init: RequestInit = {}): Promise => { capturedRequest = init; return new Response(JSON.stringify({}), { headers: { 'Content-Type': 'application/json' } }); }; @@ -192,6 +321,74 @@ describe('instantiate client', () => { expect(client2.maxRetries).toEqual(2); }); + describe('withOptions', () => { + test('creates a new client with overridden options', () => { + const client = new OpenAI({ baseURL: 'http://localhost:5000/', maxRetries: 3, apiKey: 'My API Key' }); + + const newClient = client.withOptions({ + maxRetries: 5, + baseURL: 'http://localhost:5001/', + }); + + // Verify the new client has updated options + expect(newClient.maxRetries).toEqual(5); + expect(newClient.baseURL).toEqual('http://localhost:5001/'); + + // Verify the original client is unchanged + expect(client.maxRetries).toEqual(3); + expect(client.baseURL).toEqual('http://localhost:5000/'); + + // Verify it's a different instance + expect(newClient).not.toBe(client); + expect(newClient.constructor).toBe(client.constructor); + }); + + test('inherits options from the parent client', () => { + const client = new OpenAI({ + baseURL: 'http://localhost:5000/', + defaultHeaders: { 'X-Test-Header': 'test-value' }, + defaultQuery: { 'test-param': 'test-value' }, + apiKey: 'My API Key', + }); + + const newClient = client.withOptions({ + baseURL: 'http://localhost:5001/', + }); + + // Test inherited options remain the same + expect(newClient.buildURL('/foo', null)).toEqual('http://localhost:5001/foo?test-param=test-value'); + + const { req } = newClient.buildRequest({ path: '/foo', method: 'get' }); + expect(req.headers.get('x-test-header')).toEqual('test-value'); + }); + + test('respects runtime property changes when creating new client', () => { + const client = new OpenAI({ baseURL: 'http://localhost:5000/', timeout: 1000, apiKey: 'My API Key' }); + + // Modify the client properties directly after creation + client.baseURL = 'http://localhost:6000/'; + client.timeout = 2000; + + // Create a new client with withOptions + const newClient = client.withOptions({ + maxRetries: 10, + }); + + // Verify the new client uses the updated properties, not the original ones + expect(newClient.baseURL).toEqual('http://localhost:6000/'); + expect(newClient.timeout).toEqual(2000); + expect(newClient.maxRetries).toEqual(10); + + // Original client should still have its modified properties + expect(client.baseURL).toEqual('http://localhost:6000/'); + expect(client.timeout).toEqual(2000); + expect(client.maxRetries).not.toEqual(10); + + // Verify URL building uses the updated baseURL + expect(newClient.buildURL('/bar', null)).toEqual('http://localhost:6000/bar'); + }); + }); + test('with environment variable arguments', () => { // set options via env var process.env['OPENAI_API_KEY'] = 'My API Key'; @@ -210,18 +407,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({ @@ -230,18 +415,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'))), @@ -266,7 +525,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, { @@ -284,14 +543,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, { @@ -314,13 +573,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, { @@ -353,7 +612,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, { @@ -376,12 +635,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, @@ -408,7 +670,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, @@ -433,95 +698,3 @@ describe('retries', () => { expect(count).toEqual(3); }); }); - -describe('debug()', () => { - const env = process.env; - const spy = jest.spyOn(console, 'log'); - - beforeEach(() => { - jest.resetModules(); - process.env = { ...env }; - process.env['DEBUG'] = 'true'; - }); - - afterEach(() => { - process.env = env; - }); - - test('body request object with Authorization header', function () { - // Test request body includes headers object with Authorization - const headersTest = { - headers: { - Authorization: 'fakeAuthorization', - }, - }; - debug('request', headersTest); - expect(spy).toHaveBeenCalledWith('OpenAI:DEBUG:request', { - headers: { - Authorization: 'REDACTED', - }, - }); - }); - - test('body request object with api-key header', function () { - // Test request body includes headers object with api-ley - const apiKeyTest = { - headers: { - 'api-key': 'fakeKey', - }, - }; - debug('request', apiKeyTest); - expect(spy).toHaveBeenCalledWith('OpenAI:DEBUG:request', { - headers: { - 'api-key': 'REDACTED', - }, - }); - }); - - test('header object with Authorization header', function () { - // Test headers object with authorization header - const authorizationTest = { - authorization: 'fakeValue', - }; - debug('request', authorizationTest); - expect(spy).toHaveBeenCalledWith('OpenAI:DEBUG:request', { - authorization: 'REDACTED', - }); - }); - - test('input args are not mutated', function () { - const authorizationTest = { - authorization: 'fakeValue', - }; - const client = new OpenAI({ - baseURL: 'http://localhost:5000/', - defaultHeaders: authorizationTest, - apiKey: 'api-key', - }); - - const { req } = client.buildRequest({ path: '/foo', method: 'post' }); - debug('request', authorizationTest); - expect((req.headers as Headers)['authorization']).toEqual('fakeValue'); - expect(spy).toHaveBeenCalledWith('OpenAI:DEBUG:request', { - authorization: 'REDACTED', - }); - }); - - test('input headers are not mutated', function () { - const authorizationTest = { - authorization: 'fakeValue', - }; - const client = new OpenAI({ - baseURL: 'http://localhost:5000/', - defaultHeaders: authorizationTest, - apiKey: 'api-key', - }); - - const { req } = client.buildRequest({ path: '/foo', method: 'post' }); - debug('request', { headers: req.headers }); - expect((req.headers as Headers)['authorization']).toEqual('fakeValue'); - expect(spy).toHaveBeenCalledWith('OpenAI:DEBUG:request', { - authorization: 'REDACTED', - }); - }); -}); diff --git a/tests/lib/ChatCompletionRunFunctions.test.ts b/tests/lib/ChatCompletionRunFunctions.test.ts index 496501a86..42ea3de98 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, -} from 'openai/resources/beta/chat/completions'; + type ChatCompletionStreamingToolRunnerParams, +} from 'openai/resources/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)) { @@ -131,12 +130,12 @@ class RunnerListener { readonly contents: string[] = []; readonly messages: ChatCompletionMessageParam[] = []; readonly chatCompletions: OpenAI.Chat.ChatCompletion[] = []; - readonly functionCalls: OpenAI.Chat.ChatCompletionMessage.FunctionCall[] = []; + readonly functionCalls: OpenAI.Chat.ChatCompletionMessageToolCall.Function[] = []; readonly functionCallResults: string[] = []; finalContent: string | null = null; finalMessage: ChatCompletionMessageParam | undefined; finalChatCompletion: OpenAI.Chat.ChatCompletion | undefined; - finalFunctionCall: OpenAI.Chat.ChatCompletionMessage.FunctionCall | undefined; + finalFunctionCall: OpenAI.Chat.ChatCompletionMessageToolCall.Function | undefined; finalFunctionCallResult: string | undefined; totalUsage: OpenAI.CompletionUsage | undefined; error: OpenAIError | undefined; @@ -152,13 +151,13 @@ class RunnerListener { .on('content', (content) => this.contents.push(content)) .on('message', (message) => this.messages.push(message)) .on('chatCompletion', (completion) => this.chatCompletions.push(completion)) - .on('functionCall', (functionCall) => this.functionCalls.push(functionCall)) - .on('functionCallResult', (result) => this.functionCallResults.push(result)) + .on('functionToolCall', (functionCall) => this.functionCalls.push(functionCall)) + .on('functionToolCallResult', (result) => this.functionCallResults.push(result)) .on('finalContent', (content) => (this.finalContent = content)) .on('finalMessage', (message) => (this.finalMessage = message)) .on('finalChatCompletion', (completion) => (this.finalChatCompletion = completion)) - .on('finalFunctionCall', (functionCall) => (this.finalFunctionCall = functionCall)) - .on('finalFunctionCallResult', (result) => (this.finalFunctionCallResult = result)) + .on('finalFunctionToolCall', (functionCall) => (this.finalFunctionCall = functionCall)) + .on('finalFunctionToolCallResult', (result) => (this.finalFunctionCallResult = result)) .on('totalUsage', (usage) => (this.totalUsage = usage)) .on('error', (error) => (this.error = error)) .on('abort', (error) => ((this.error = error), (this.gotAbort = true))) @@ -176,8 +175,8 @@ class RunnerListener { await expect(this.runner.finalChatCompletion()).rejects.toThrow(error); await expect(this.runner.finalMessage()).rejects.toThrow(error); await expect(this.runner.finalContent()).rejects.toThrow(error); - await expect(this.runner.finalFunctionCall()).rejects.toThrow(error); - await expect(this.runner.finalFunctionCallResult()).rejects.toThrow(error); + await expect(this.runner.finalFunctionToolCall()).rejects.toThrow(error); + await expect(this.runner.finalFunctionToolCallResult()).rejects.toThrow(error); await expect(this.runner.totalUsage()).rejects.toThrow(error); await expect(this.runner.done()).rejects.toThrow(error); } else { @@ -215,11 +214,11 @@ class RunnerListener { expect(this.finalChatCompletion).toEqual(this.chatCompletions[this.chatCompletions.length - 1]); expect(await this.runner.finalChatCompletion()).toEqual(this.finalChatCompletion); expect(this.finalFunctionCall).toEqual(this.functionCalls[this.functionCalls.length - 1]); - expect(await this.runner.finalFunctionCall()).toEqual(this.finalFunctionCall); + expect(await this.runner.finalFunctionToolCall()).toEqual(this.finalFunctionCall); expect(this.finalFunctionCallResult).toEqual( this.functionCallResults[this.functionCallResults.length - 1], ); - expect(await this.runner.finalFunctionCallResult()).toEqual(this.finalFunctionCallResult); + expect(await this.runner.finalFunctionToolCallResult()).toEqual(this.finalFunctionCallResult); expect(this.chatCompletions).toEqual(this.runner.allChatCompletions()); expect(this.messages).toEqual(this.runner.messages.slice(-this.messages.length)); if (this.chatCompletions.some((c) => c.usage)) { @@ -248,13 +247,13 @@ class StreamingRunnerListener { readonly eventContents: [string, string][] = []; readonly eventMessages: ChatCompletionMessageParam[] = []; readonly eventChatCompletions: OpenAI.Chat.ChatCompletion[] = []; - readonly eventFunctionCalls: OpenAI.Chat.ChatCompletionMessage.FunctionCall[] = []; + readonly eventFunctionCalls: OpenAI.Chat.ChatCompletionMessageToolCall.Function[] = []; readonly eventFunctionCallResults: string[] = []; finalContent: string | null = null; finalMessage: ChatCompletionMessageParam | undefined; finalChatCompletion: OpenAI.Chat.ChatCompletion | undefined; - finalFunctionCall: OpenAI.Chat.ChatCompletionMessage.FunctionCall | undefined; + finalFunctionCall: OpenAI.Chat.ChatCompletionMessageToolCall.Function | undefined; finalFunctionCallResult: string | undefined; error: OpenAIError | undefined; gotConnect = false; @@ -267,13 +266,13 @@ class StreamingRunnerListener { .on('content', (delta, snapshot) => this.eventContents.push([delta, snapshot])) .on('message', (message) => this.eventMessages.push(message)) .on('chatCompletion', (completion) => this.eventChatCompletions.push(completion)) - .on('functionCall', (functionCall) => this.eventFunctionCalls.push(functionCall)) - .on('functionCallResult', (result) => this.eventFunctionCallResults.push(result)) + .on('functionToolCall', (functionCall) => this.eventFunctionCalls.push(functionCall)) + .on('functionToolCallResult', (result) => this.eventFunctionCallResults.push(result)) .on('finalContent', (content) => (this.finalContent = content)) .on('finalMessage', (message) => (this.finalMessage = message)) .on('finalChatCompletion', (completion) => (this.finalChatCompletion = completion)) - .on('finalFunctionCall', (functionCall) => (this.finalFunctionCall = functionCall)) - .on('finalFunctionCallResult', (result) => (this.finalFunctionCallResult = result)) + .on('finalFunctionToolCall', (functionCall) => (this.finalFunctionCall = functionCall)) + .on('finalFunctionToolCallResult', (result) => (this.finalFunctionCallResult = result)) .on('error', (error) => (this.error = error)) .on('abort', (abort) => (this.error = abort)) .on('end', () => (this.gotEnd = true)); @@ -286,8 +285,8 @@ class StreamingRunnerListener { await expect(this.runner.finalChatCompletion()).rejects.toThrow(error); await expect(this.runner.finalMessage()).rejects.toThrow(error); await expect(this.runner.finalContent()).rejects.toThrow(error); - await expect(this.runner.finalFunctionCall()).rejects.toThrow(error); - await expect(this.runner.finalFunctionCallResult()).rejects.toThrow(error); + await expect(this.runner.finalFunctionToolCall()).rejects.toThrow(error); + await expect(this.runner.finalFunctionToolCallResult()).rejects.toThrow(error); await expect(this.runner.done()).rejects.toThrow(error); } else { expect(this.error).toBeUndefined(); @@ -319,11 +318,11 @@ class StreamingRunnerListener { expect(this.finalChatCompletion).toEqual(this.eventChatCompletions[this.eventChatCompletions.length - 1]); expect(await this.runner.finalChatCompletion()).toEqual(this.finalChatCompletion); expect(this.finalFunctionCall).toEqual(this.eventFunctionCalls[this.eventFunctionCalls.length - 1]); - expect(await this.runner.finalFunctionCall()).toEqual(this.finalFunctionCall); + expect(await this.runner.finalFunctionToolCall()).toEqual(this.finalFunctionCall); expect(this.finalFunctionCallResult).toEqual( this.eventFunctionCallResults[this.eventFunctionCallResults.length - 1], ); - expect(await this.runner.finalFunctionCallResult()).toEqual(this.finalFunctionCallResult); + expect(await this.runner.finalFunctionToolCallResult()).toEqual(this.finalFunctionCallResult); expect(this.eventChatCompletions).toEqual(this.runner.allChatCompletions()); expect(this.eventMessages).toEqual(this.runner.messages.slice(-this.eventMessages.length)); if (error) { @@ -340,7 +339,7 @@ class StreamingRunnerListener { function _typeTests() { const openai = new OpenAI(); - openai.beta.chat.completions.runTools({ + openai.chat.completions.runTools({ messages: [ { role: 'user', content: 'can you tell me how many properties are in {"a": 1, "b": 2, "c": 3}' }, ], @@ -381,7 +380,7 @@ function _typeTests() { }, ], }); - openai.beta.chat.completions.runTools({ + openai.chat.completions.runTools({ messages: [ { role: 'user', content: 'can you tell me how many properties are in {"a": 1, "b": 2, "c": 3}' }, ], @@ -397,7 +396,7 @@ function _typeTests() { }), ], }); - openai.beta.chat.completions.runTools({ + openai.chat.completions.runTools({ messages: [ { role: 'user', content: 'can you tell me how many properties are in {"a": 1, "b": 2, "c": 3}' }, ], @@ -439,7 +438,7 @@ function _typeTests() { }), ], }); - openai.beta.chat.completions.runTools({ + openai.chat.completions.runTools({ messages: [ { role: 'user', content: 'can you tell me how many properties are in {"a": 1, "b": 2, "c": 3}' }, ], @@ -501,7 +500,7 @@ describe('resource completions', () => { const openai = new OpenAI({ apiKey: 'something1234', baseURL: 'http://127.0.0.1:4010', fetch }); - const runner = openai.beta.chat.completions.runTools({ + const runner = openai.chat.completions.runTools({ messages: [{ role: 'user', content: 'tell me what the weather is like' }], model: 'gpt-3.5-turbo', tools: [ @@ -640,7 +639,7 @@ describe('resource completions', () => { const openai = new OpenAI({ apiKey: 'something1234', baseURL: 'http://127.0.0.1:4010', fetch }); const controller = new AbortController(); - const runner = openai.beta.chat.completions.runTools( + const runner = openai.chat.completions.runTools( { messages: [{ role: 'user', content: 'tell me what the weather is like' }], model: 'gpt-3.5-turbo', @@ -727,7 +726,7 @@ describe('resource completions', () => { const openai = new OpenAI({ apiKey: 'something1234', baseURL: 'http://127.0.0.1:4010', fetch }); - const runner = openai.beta.chat.completions.runTools({ + const runner = openai.chat.completions.runTools({ messages: [ { role: 'user', @@ -887,7 +886,7 @@ describe('resource completions', () => { const openai = new OpenAI({ apiKey: 'something1234', baseURL: 'http://127.0.0.1:4010', fetch }); - const runner = openai.beta.chat.completions.runTools({ + const runner = openai.chat.completions.runTools({ messages: [ { role: 'user', @@ -1136,7 +1135,7 @@ describe('resource completions', () => { const openai = new OpenAI({ apiKey: 'something1234', baseURL: 'http://127.0.0.1:4010', fetch }); - const runner = openai.beta.chat.completions.runTools({ + const runner = openai.chat.completions.runTools({ messages: [{ role: 'user', content: 'tell me what the weather is like' }], model: 'gpt-3.5-turbo', tool_choice: { @@ -1224,7 +1223,7 @@ describe('resource completions', () => { const openai = new OpenAI({ apiKey: 'something1234', baseURL: 'http://127.0.0.1:4010', fetch }); - const runner = openai.beta.chat.completions.runTools({ + const runner = openai.chat.completions.runTools({ messages: [{ role: 'user', content: 'tell me what the weather is like' }], model: 'gpt-3.5-turbo', tools: [ @@ -1460,7 +1459,7 @@ describe('resource completions', () => { const openai = new OpenAI({ apiKey: 'something1234', baseURL: 'http://127.0.0.1:4010', fetch }); - const runner = openai.beta.chat.completions.runTools({ + const runner = openai.chat.completions.runTools({ stream: true, messages: [{ role: 'user', content: 'tell me what the weather is like' }], model: 'gpt-3.5-turbo', @@ -1584,7 +1583,7 @@ describe('resource completions', () => { const openai = new OpenAI({ apiKey: 'something1234', baseURL: 'http://127.0.0.1:4010', fetch }); const controller = new AbortController(); - const runner = openai.beta.chat.completions.runTools( + const runner = openai.chat.completions.runTools( { stream: true, messages: [{ role: 'user', content: 'tell me what the weather is like' }], @@ -1604,7 +1603,7 @@ describe('resource completions', () => { }, { signal: controller.signal }, ); - runner.on('functionCallResult', () => controller.abort()); + runner.on('functionToolCallResult', () => controller.abort()); const listener = new StreamingRunnerListener(runner); await handleRequest(async function* (request): AsyncIterable { @@ -1668,7 +1667,7 @@ describe('resource completions', () => { const openai = new OpenAI({ apiKey: 'something1234', baseURL: 'http://127.0.0.1:4010', fetch }); - const runner = openai.beta.chat.completions.runTools({ + const runner = openai.chat.completions.runTools({ stream: true, messages: [ { @@ -1806,7 +1805,7 @@ describe('resource completions', () => { const openai = new OpenAI({ apiKey: 'something1234', baseURL: 'http://127.0.0.1:4010', fetch }); - const runner = openai.beta.chat.completions.runTools({ + const runner = openai.chat.completions.runTools({ stream: true, messages: [ { @@ -2008,7 +2007,7 @@ describe('resource completions', () => { const openai = new OpenAI({ apiKey: 'something1234', baseURL: 'http://127.0.0.1:4010', fetch }); - const runner = openai.beta.chat.completions.runTools({ + const runner = openai.chat.completions.runTools({ stream: true, messages: [{ role: 'user', content: 'tell me what the weather is like' }], model: 'gpt-3.5-turbo', @@ -2094,7 +2093,7 @@ describe('resource completions', () => { const openai = new OpenAI({ apiKey: 'something1234', baseURL: 'http://127.0.0.1:4010', fetch }); - const runner = openai.beta.chat.completions.runTools({ + const runner = openai.chat.completions.runTools({ stream: true, messages: [{ role: 'user', content: 'tell me what the weather is like' }], model: 'gpt-3.5-turbo', @@ -2318,7 +2317,7 @@ describe('resource completions', () => { const openai = new OpenAI({ apiKey: 'something1234', baseURL: 'http://127.0.0.1:4010', fetch }); - const runner = openai.beta.chat.completions.stream({ + const runner = openai.chat.completions.stream({ stream: true, messages: [{ role: 'user', content: 'tell me what the weather is like' }], model: 'gpt-3.5-turbo', @@ -2356,7 +2355,7 @@ describe('resource completions', () => { const openai = new OpenAI({ apiKey: 'something1234', baseURL: 'http://127.0.0.1:4010', fetch }); - const runner = openai.beta.chat.completions.stream({ + const runner = openai.chat.completions.stream({ stream: true, messages: [{ role: 'user', content: 'tell me what the weather is like' }], model: 'gpt-3.5-turbo', @@ -2395,7 +2394,7 @@ describe('resource completions', () => { const openai = new OpenAI({ apiKey: '...', fetch }); - const stream = openai.beta.chat.completions.stream( + const stream = openai.chat.completions.stream( { max_tokens: 1024, model: 'gpt-3.5-turbo', @@ -2419,7 +2418,7 @@ describe('resource completions', () => { const openai = new OpenAI({ apiKey: '...', fetch }); - const stream = openai.beta.chat.completions.stream( + const stream = openai.chat.completions.stream( { max_tokens: 1024, model: 'gpt-3.5-turbo', diff --git a/tests/lib/ChatCompletionStream.test.ts b/tests/lib/ChatCompletionStream.test.ts index 34c5fd204..7d78b712a 100644 --- a/tests/lib/ChatCompletionStream.test.ts +++ b/tests/lib/ChatCompletionStream.test.ts @@ -8,7 +8,7 @@ jest.setTimeout(1000 * 30); describe('.stream()', () => { it('works', async () => { const stream = await makeStreamSnapshotRequest((openai) => - openai.beta.chat.completions.stream({ + openai.chat.completions.stream({ model: 'gpt-4o-2024-08-06', messages: [ { @@ -49,7 +49,7 @@ describe('.stream()', () => { const stream = ( await makeStreamSnapshotRequest((openai) => - openai.beta.chat.completions.stream({ + openai.chat.completions.stream({ model: 'gpt-4o-2024-08-06', messages: [ { @@ -208,7 +208,7 @@ describe('.stream()', () => { const stream = ( await makeStreamSnapshotRequest((openai) => - openai.beta.chat.completions.stream({ + openai.chat.completions.stream({ model: 'gpt-4o-2024-08-06', messages: [ { diff --git a/tests/lib/azure.test.ts b/tests/lib/azure.test.ts index 430efbe57..ef80e275b 100644 --- a/tests/lib/azure.test.ts +++ b/tests/lib/azure.test.ts @@ -1,7 +1,8 @@ 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'; + +const defaultFetch = fetch; const apiVersion = '2024-02-15-preview'; const deployment = 'deployment'; @@ -31,7 +32,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 +41,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 +50,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); }); test('includes retry count', () => { @@ -61,7 +62,7 @@ describe('instantiate azure client', () => { }, { retryCount: 1 }, ); - expect((req.headers as Headers)['x-stainless-retry-count']).toEqual('1'); + expect(req.headers.get('x-stainless-retry-count')).toEqual('1'); }); }); @@ -238,7 +239,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/', @@ -267,7 +268,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) { @@ -279,10 +280,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() { @@ -327,10 +327,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({ @@ -341,110 +339,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}`, + }); }); }); @@ -456,126 +472,126 @@ 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('handles audio translations', 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/deployments/${deployment}/audio/translations?api-version=${apiVersion}`, - ); + 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('handles audio transcriptions', 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/deployments/${deployment}/audio/transcriptions?api-version=${apiVersion}`, - ); + 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({ @@ -584,10 +600,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 fa8123f5c..74cca7253 100644 --- a/tests/lib/parser.test.ts +++ b/tests/lib/parser.test.ts @@ -8,7 +8,7 @@ describe('.parse()', () => { describe('zod', () => { it('deserialises response_format', async () => { const completion = await makeSnapshotRequest((openai) => - openai.beta.chat.completions.parse({ + openai.chat.completions.parse({ model: 'gpt-4o-2024-08-06', messages: [ { @@ -60,7 +60,7 @@ describe('.parse()', () => { ); const completion = await makeSnapshotRequest((openai) => - openai.beta.chat.completions.parse({ + openai.chat.completions.parse({ model: 'gpt-4o-2024-08-06', messages: [ { @@ -448,7 +448,7 @@ describe('.parse()', () => { const completion = await makeSnapshotRequest( (openai) => - openai.beta.chat.completions.parse({ + openai.chat.completions.parse({ model: 'gpt-4o-2024-08-06', messages: [ { @@ -698,7 +698,7 @@ describe('.parse()', () => { const completion = await makeSnapshotRequest( (openai) => - openai.beta.chat.completions.parse({ + openai.chat.completions.parse({ model: 'gpt-4o-2024-08-06', messages: [ { @@ -905,7 +905,7 @@ describe('.parse()', () => { const completion = await makeSnapshotRequest( (openai) => - openai.beta.chat.completions.parse({ + openai.chat.completions.parse({ model: 'gpt-4o-2024-08-06', messages: [ { @@ -1030,7 +1030,7 @@ describe('.parse()', () => { const completion = await makeSnapshotRequest( (openai) => - openai.beta.chat.completions.parse({ + openai.chat.completions.parse({ model: 'gpt-4o-2024-08-06', messages: [ { diff --git a/tests/log.test.ts b/tests/log.test.ts new file mode 100644 index 000000000..1900e83b2 --- /dev/null +++ b/tests/log.test.ts @@ -0,0 +1,119 @@ +import OpenAI, { ClientOptions } from 'openai/index'; + +const opts: ClientOptions = { + apiKey: 'example-api-key', + baseURL: 'http://localhost:5000/', + logLevel: 'debug', + fetch: (url) => { + return Promise.resolve( + new Response(JSON.stringify({ url, custom: true }), { + headers: { 'Content-Type': 'application/json' }, + }), + ); + }, +}; + +describe('debug()', () => { + const env = process.env; + const spy = jest.spyOn(console, 'debug'); + + beforeEach(() => { + jest.resetModules(); + process.env = { ...env }; + process.env['DEBUG'] = 'true'; + }); + + afterEach(() => { + process.env = env; + }); + + test('body request object with Authorization header', async function () { + const client = new OpenAI(opts); + await client.post('/example', {}); + + // Check that console.debug was called with the redacted authorization header + expect(spy).toHaveBeenCalledWith( + expect.stringContaining('[log_'), + expect.objectContaining({ + headers: expect.objectContaining({ + authorization: '***', + }), + }), + ); + }); + + test('header object with Authorization header', async function () { + // Test headers object with authorization header + const client = new OpenAI({ + ...opts, + defaultHeaders: { + authorization: 'fakeValue', + }, + }); + await client.post('/example', {}); + + expect(spy).toHaveBeenCalledWith( + expect.stringContaining('[log_'), + expect.objectContaining({ + headers: expect.objectContaining({ + authorization: '***', + }), + }), + ); + }); + + test('input args are not mutated', async function () { + const authorizationTest = { + authorization: 'fakeValue', + }; + const client = new OpenAI({ + ...opts, + defaultHeaders: authorizationTest, + }); + + const { req } = client.buildRequest({ path: '/foo', method: 'post' }); + await client.post('/foo', {}); + + // Verify that the original headers weren't mutated + expect(authorizationTest.authorization).toEqual('fakeValue'); + expect((req.headers as Headers).get('authorization')).toEqual('fakeValue'); + + expect(spy).toHaveBeenCalledWith( + expect.stringContaining('[log_'), + expect.objectContaining({ + headers: expect.objectContaining({ + authorization: '***', + }), + }), + ); + }); + + test('input headers are not mutated', async function () { + const authorizationTest = { + authorization: 'fakeValue', + }; + const client = new OpenAI({ + baseURL: 'http://localhost:5000/', + defaultHeaders: authorizationTest, + apiKey: 'api-key', + logLevel: 'debug', + fetch: opts.fetch, + }); + + const { req } = client.buildRequest({ path: '/foo', method: 'post' }); + await client.post('/foo', {}); + + // Verify that the original headers weren't mutated + expect(authorizationTest.authorization).toEqual('fakeValue'); + expect((req.headers as Headers).get('authorization')).toEqual('fakeValue'); + + expect(spy).toHaveBeenCalledWith( + expect.stringContaining('[log_'), + expect.objectContaining({ + headers: expect.objectContaining({ + authorization: '***', + }), + }), + ); + }); +}); 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..e17ce80af 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: 'example-api-key' }); 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 b9a38f208..a1abbaba4 100644 --- a/tests/streaming.test.ts +++ b/tests/streaming.test.ts @@ -1,7 +1,6 @@ -import { Response } from 'node-fetch'; -import { PassThrough } from 'stream'; import assert from 'assert'; -import { _iterSSEMessages } from 'openai/streaming'; +import { _iterSSEMessages } from 'openai/core/streaming'; +import { ReadableStreamFrom } from 'openai/internal/shims'; describe('streaming decoding', () => { test('basic', async () => { @@ -11,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 ](); @@ -29,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 ](); @@ -48,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 ](); @@ -69,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 ](); @@ -97,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 ](); @@ -126,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 ](); @@ -147,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 ](); @@ -172,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 ](); @@ -205,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 ](); @@ -218,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..d66ed412f 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/core/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/core/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/tsc-multi.json b/tsc-multi.json index 4facad5ad..170bac7a4 100644 --- a/tsc-multi.json +++ b/tsc-multi.json @@ -1,7 +1,7 @@ { "targets": [ - { "extname": ".js", "module": "commonjs" }, - { "extname": ".mjs", "module": "esnext" } + { "extname": ".js", "module": "commonjs", "shareHelpers": "internal/tslib.js" }, + { "extname": ".mjs", "module": "esnext", "shareHelpers": "internal/tslib.mjs" } ], "projects": ["tsconfig.build.json"] } diff --git a/tsconfig.build.json b/tsconfig.build.json index 45811cb8b..57578eb44 100644 --- a/tsconfig.build.json +++ b/tsconfig.build.json @@ -1,12 +1,12 @@ { "extends": "./tsconfig.json", "include": ["dist/src"], - "exclude": ["dist/src/_shims/*-deno.ts"], + "exclude": [], "compilerOptions": { "rootDir": "./dist/src", "paths": { "openai/*": ["dist/src/*"], - "openai": ["dist/src/index.ts"], + "openai": ["dist/src/index.ts"] }, "noEmit": false, "declaration": true, 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..2e1c8e421 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"] }, @@ -32,7 +31,7 @@ "noUncheckedIndexedAccess": true, "noImplicitOverride": true, "noPropertyAccessFromIndexSignature": true, - "isolatedModules": true, + "isolatedModules": true, "skipLibCheck": true } diff --git a/yarn.lock b/yarn.lock index ad5fb7630..c8dd560c5 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== -"@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/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== + +"@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,15 +937,12 @@ 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" @@ -882,9 +950,9 @@ integrity sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw== "@types/ws@^8.5.13": - version "8.5.13" - resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.13.tgz#6414c280875e2691d0d1e080b05addbf5cb91e20" - integrity sha512-osM/gWBTPKgHV8XkTunnegTRIsvF6owmf5w+JtAfOw472dptdm0dlGv4xCt6GwQRcC2XVOvvRE/0bAoQcL2QkA== + 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" "*" @@ -900,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.31.1": + version "8.31.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.31.1.tgz#62f1befe59647524994e89de4516d8dcba7a850a" + integrity sha512-oUlH4h1ABavI4F0Xnl8/fOtML/eu8nI2A1nYd+f+55XI0BLu+RIqKoCiZKNo6DtqZBEQm5aNKA20G3Z5w3R6GQ== 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.31.1" + "@typescript-eslint/type-utils" "8.31.1" + "@typescript-eslint/utils" "8.31.1" + "@typescript-eslint/visitor-keys" "8.31.1" 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.31.1": + version "8.31.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.31.1.tgz#e9b0ccf30d37dde724ee4d15f4dbc195995cce1b" + integrity sha512-oU/OtYVydhXnumd0BobL9rkJg7wFJ9bFFPmSmB/bf/XWN85hlViji59ko6bSKBXyseT9V8l+CN1nwmlbiN0G7Q== 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.31.1" + "@typescript-eslint/types" "8.31.1" + "@typescript-eslint/typescript-estree" "8.31.1" + "@typescript-eslint/visitor-keys" "8.31.1" 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.31.1": + version "8.31.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.31.1.tgz#1eb52e76878f545e4add142e0d8e3e97e7aa443b" + integrity sha512-BMNLOElPxrtNQMIsFHE+3P0Yf1z0dJqV9zLdDxN/xLlWMlXK/ApEsVEKzpizg9oal8bAT5Sc7+ocal7AC1HCVw== dependencies: - "@typescript-eslint/types" "6.21.0" - "@typescript-eslint/visitor-keys" "6.21.0" + "@typescript-eslint/types" "8.31.1" + "@typescript-eslint/visitor-keys" "8.31.1" -"@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.31.1": + version "8.31.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.31.1.tgz#be0f438fb24b03568e282a0aed85f776409f970c" + integrity sha512-fNaT/m9n0+dpSp8G/iOQ05GoHYXbxw81x+yvr7TArTuZuCA6VVKbqWYVZrV5dVagpDTtj/O8k5HBEE/p/HM5LA== dependencies: - "@typescript-eslint/typescript-estree" "6.21.0" - "@typescript-eslint/utils" "6.21.0" + "@typescript-eslint/typescript-estree" "8.31.1" + "@typescript-eslint/utils" "8.31.1" 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.31.1": + version "8.31.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.31.1.tgz#478ed6f7e8aee1be7b63a60212b6bffe1423b5d4" + integrity sha512-SfepaEFUDQYRoA70DD9GtytljBePSj17qPxFHA/h3eg6lPTqGJ5mWOtbXCk1YrVU1cTJRd14nhaXWFu0l2troQ== -"@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.31.1": + version "8.31.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.31.1.tgz#37792fe7ef4d3021c7580067c8f1ae66daabacdf" + integrity sha512-kaA0ueLe2v7KunYOyWYtlf/QhhZb7+qh4Yw6Ni5kgukMIG+iP773tjgBiLWIXYumWCwEq3nLW+TUywEp8uEeag== dependencies: - "@typescript-eslint/types" "6.21.0" - "@typescript-eslint/visitor-keys" "6.21.0" + "@typescript-eslint/types" "8.31.1" + "@typescript-eslint/visitor-keys" "8.31.1" 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.31.1": + version "8.31.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.31.1.tgz#5628ea0393598a0b2f143d0fc6d019f0dee9dd14" + integrity sha512-2DSI4SNfF5T4oRveQ4nUrSjUqjMND0nLq9rEkz0gfGr3tg0S5KB6DhwR+WZPCjzkZl3cH+4x2ce3EsL50FubjQ== 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/scope-manager" "8.31.1" + "@typescript-eslint/types" "8.31.1" + "@typescript-eslint/typescript-estree" "8.31.1" -"@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== +"@typescript-eslint/visitor-keys@8.31.1": + version "8.31.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.31.1.tgz#6742b0e3ba1e0c1e35bdaf78c03e759eb8dd8e75" + integrity sha512-I+/rgqOVBn6f0o7NDTmAPWWC6NuqhV174lfYvAm9fUaWeiefLdux9/YI3/nLugEn9L8fcSi0XmpKi/r5u0nmpw== dependencies: - "@typescript-eslint/types" "6.21.0" - eslint-visitor-keys "^3.4.1" - -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== - dependencies: - event-target-shim "^5.0.0" + "@typescript-eslint/types" "8.31.1" + eslint-visitor-keys "^4.2.0" acorn-jsx@^5.3.2: version "5.3.2" @@ -1003,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" @@ -1047,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" @@ -1071,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" @@ -1096,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" @@ -1171,18 +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== - -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" - -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" + synckit "^0.9.1" -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,12 +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== +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-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 "^3.0.4" + flat-cache "^4.0.0" fill-range@^7.1.1: version "7.1.1" @@ -1776,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" @@ -1846,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== @@ -1877,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" @@ -1928,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" @@ -1938,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" @@ -1957,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== @@ -2013,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" @@ -2045,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" @@ -2520,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" @@ -2545,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" @@ -2592,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" @@ -2625,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== @@ -2643,73 +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== +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" @@ -2726,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" @@ -2733,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" @@ -2754,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" @@ -2847,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" @@ -2862,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" @@ -2904,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" @@ -2938,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" @@ -3013,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" @@ -3034,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" @@ -3061,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" @@ -3083,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" @@ -3166,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" @@ -3188,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== @@ -3202,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: @@ -3224,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" @@ -3251,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" @@ -3294,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.4/tsc-multi-1.1.4.tgz": + version "1.1.4" + resolved "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.4/tsc-multi-1.1.4.tgz#cbed459a9e902f5295ec3daaf1c7aa3b10427e55" 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" @@ -3319,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" @@ -3341,30 +3349,44 @@ 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@^4.8.2: - version "4.9.5" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" - integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== +typescript-eslint@8.31.1: + version "8.31.1" + resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-8.31.1.tgz#b77ab1e48ced2daab9225ff94bab54391a4af69b" + integrity sha512-j6DsEotD/fH39qKzXTQRwYYWlt7D+0HmfpOK+DVhwJOFLcdmn92hq3mBb7HlKJHbjjI/gTOqEcc9d6JfpFf/VA== + dependencies: + "@typescript-eslint/eslint-plugin" "8.31.1" + "@typescript-eslint/parser" "8.31.1" + "@typescript-eslint/utils" "8.31.1" + +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@5.8.3: + version "5.8.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.8.3.tgz#92f8a3e5e3cf497356f4178c34cd65a7f5e8440e" + integrity sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ== undici-types@~5.26.4: version "5.26.5" 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" @@ -3400,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" @@ -3407,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" @@ -3474,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== @@ -3503,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==