From 41a9bc8742d6236822289fa017e2122e45b17584 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 21 May 2025 11:47:55 +0000 Subject: [PATCH 01/91] initial commit --- .devcontainer/devcontainer.json | 15 + .github/workflows/ci.yml | 81 + .gitignore | 10 + .prettierignore | 7 + .prettierrc.json | 7 + .stats.yml | 4 + Brewfile | 1 + CONTRIBUTING.md | 93 + LICENSE | 201 + README.md | 412 +- SECURITY.md | 23 + api.md | 77 + bin/publish-npm | 25 + eslint.config.mjs | 42 + examples/.keep | 4 + jest.config.ts | 22 + package.json | 72 + scripts/bootstrap | 18 + scripts/build | 53 + scripts/format | 12 + scripts/lint | 21 + scripts/mock | 41 + scripts/test | 56 + scripts/utils/attw-report.cjs | 24 + scripts/utils/check-is-in-git-install.sh | 9 + scripts/utils/check-version.cjs | 20 + scripts/utils/fix-index-exports.cjs | 17 + scripts/utils/git-swap.sh | 13 + scripts/utils/make-dist-package-json.cjs | 21 + scripts/utils/postprocess-files.cjs | 94 + scripts/utils/upload-artifact.sh | 25 + src/api-promise.ts | 2 + src/client.ts | 794 ++++ src/core/README.md | 3 + src/core/api-promise.ts | 92 + src/core/error.ts | 130 + src/core/resource.ts | 11 + src/core/uploads.ts | 2 + src/error.ts | 2 + src/index.ts | 22 + src/internal/README.md | 3 + src/internal/builtin-types.ts | 93 + src/internal/detect-platform.ts | 196 + src/internal/errors.ts | 33 + src/internal/headers.ts | 97 + src/internal/parse.ts | 50 + src/internal/request-options.ts | 37 + src/internal/shim-types.d.ts | 28 + src/internal/shims.ts | 107 + src/internal/to-file.ts | 154 + src/internal/types.ts | 92 + src/internal/uploads.ts | 187 + src/internal/utils.ts | 8 + src/internal/utils/base64.ts | 40 + src/internal/utils/bytes.ts | 32 + src/internal/utils/env.ts | 18 + src/internal/utils/log.ts | 127 + src/internal/utils/path.ts | 65 + src/internal/utils/sleep.ts | 3 + src/internal/utils/uuid.ts | 17 + src/internal/utils/values.ts | 102 + src/lib/.keep | 4 + src/resource.ts | 2 + src/resources.ts | 1 + src/resources/events.ts | 618 +++ src/resources/files.ts | 247 ++ src/resources/image-operations.ts | 1520 ++++++++ src/resources/index.ts | 36 + src/resources/pdf-operations.ts | 1054 ++++++ src/resources/tasks.ts | 1735 +++++++++ src/uploads.ts | 2 + src/version.ts | 1 + tests/api-resources/events.test.ts | 30 + tests/api-resources/files.test.ts | 77 + tests/api-resources/image-operations.test.ts | 132 + tests/api-resources/pdf-operations.test.ts | 93 + tests/api-resources/tasks.test.ts | 42 + tests/base64.test.ts | 80 + tests/buildHeaders.test.ts | 88 + tests/form.test.ts | 85 + tests/index.test.ts | 718 ++++ tests/path.test.ts | 318 ++ tests/stringifyQuery.test.ts | 29 + tests/uploads.test.ts | 107 + tsc-multi.json | 7 + tsconfig.build.json | 18 + tsconfig.deno.json | 15 + tsconfig.dist-src.json | 11 + tsconfig.json | 38 + yarn.lock | 3506 ++++++++++++++++++ 90 files changed, 14680 insertions(+), 1 deletion(-) create mode 100644 .devcontainer/devcontainer.json create mode 100644 .github/workflows/ci.yml create mode 100644 .gitignore create mode 100644 .prettierignore create mode 100644 .prettierrc.json create mode 100644 .stats.yml create mode 100644 Brewfile create mode 100644 CONTRIBUTING.md create mode 100644 LICENSE create mode 100644 SECURITY.md create mode 100644 api.md create mode 100644 bin/publish-npm create mode 100644 eslint.config.mjs create mode 100644 examples/.keep create mode 100644 jest.config.ts create mode 100644 package.json create mode 100755 scripts/bootstrap create mode 100755 scripts/build create mode 100755 scripts/format create mode 100755 scripts/lint create mode 100755 scripts/mock create mode 100755 scripts/test create mode 100644 scripts/utils/attw-report.cjs create mode 100755 scripts/utils/check-is-in-git-install.sh create mode 100644 scripts/utils/check-version.cjs create mode 100644 scripts/utils/fix-index-exports.cjs create mode 100755 scripts/utils/git-swap.sh create mode 100644 scripts/utils/make-dist-package-json.cjs create mode 100644 scripts/utils/postprocess-files.cjs create mode 100755 scripts/utils/upload-artifact.sh create mode 100644 src/api-promise.ts create mode 100644 src/client.ts create mode 100644 src/core/README.md create mode 100644 src/core/api-promise.ts create mode 100644 src/core/error.ts create mode 100644 src/core/resource.ts create mode 100644 src/core/uploads.ts create mode 100644 src/error.ts create mode 100644 src/index.ts create mode 100644 src/internal/README.md create mode 100644 src/internal/builtin-types.ts create mode 100644 src/internal/detect-platform.ts create mode 100644 src/internal/errors.ts create mode 100644 src/internal/headers.ts create mode 100644 src/internal/parse.ts create mode 100644 src/internal/request-options.ts create mode 100644 src/internal/shim-types.d.ts create mode 100644 src/internal/shims.ts create mode 100644 src/internal/to-file.ts create mode 100644 src/internal/types.ts create mode 100644 src/internal/uploads.ts create mode 100644 src/internal/utils.ts create mode 100644 src/internal/utils/base64.ts create mode 100644 src/internal/utils/bytes.ts create mode 100644 src/internal/utils/env.ts create mode 100644 src/internal/utils/log.ts create mode 100644 src/internal/utils/path.ts create mode 100644 src/internal/utils/sleep.ts create mode 100644 src/internal/utils/uuid.ts create mode 100644 src/internal/utils/values.ts create mode 100644 src/lib/.keep create mode 100644 src/resource.ts create mode 100644 src/resources.ts create mode 100644 src/resources/events.ts create mode 100644 src/resources/files.ts create mode 100644 src/resources/image-operations.ts create mode 100644 src/resources/index.ts create mode 100644 src/resources/pdf-operations.ts create mode 100644 src/resources/tasks.ts create mode 100644 src/uploads.ts create mode 100644 src/version.ts create mode 100644 tests/api-resources/events.test.ts create mode 100644 tests/api-resources/files.test.ts create mode 100644 tests/api-resources/image-operations.test.ts create mode 100644 tests/api-resources/pdf-operations.test.ts create mode 100644 tests/api-resources/tasks.test.ts create mode 100644 tests/base64.test.ts create mode 100644 tests/buildHeaders.test.ts create mode 100644 tests/form.test.ts create mode 100644 tests/index.test.ts create mode 100644 tests/path.test.ts create mode 100644 tests/stringifyQuery.test.ts create mode 100644 tests/uploads.test.ts create mode 100644 tsc-multi.json create mode 100644 tsconfig.build.json create mode 100644 tsconfig.deno.json create mode 100644 tsconfig.dist-src.json create mode 100644 tsconfig.json create mode 100644 yarn.lock diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..43fd5a7 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,15 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/debian +{ + "name": "Development", + "image": "mcr.microsoft.com/devcontainers/typescript-node:latest", + "features": { + "ghcr.io/devcontainers/features/node:1": {} + }, + "postCreateCommand": "yarn install", + "customizations": { + "vscode": { + "extensions": ["esbenp.prettier-vscode"] + } + } +} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..a13c266 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,81 @@ +name: CI +on: + push: + branches-ignore: + - 'generated' + - 'codegen/**' + - 'integrated/**' + - 'stl-preview-head/**' + - 'stl-preview-base/**' + +jobs: + lint: + timeout-minutes: 10 + name: lint + runs-on: ${{ github.repository == 'stainless-sdks/scan-documents-typescript' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} + steps: + - uses: actions/checkout@v4 + + - name: Set up Node + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: Bootstrap + run: ./scripts/bootstrap + + - name: Check types + run: ./scripts/lint + + build: + timeout-minutes: 5 + name: build + runs-on: ${{ github.repository == 'stainless-sdks/scan-documents-typescript' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} + permissions: + contents: read + id-token: write + steps: + - uses: actions/checkout@v4 + + - name: Set up Node + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: Bootstrap + run: ./scripts/bootstrap + + - name: Check build + run: ./scripts/build + + - name: Get GitHub OIDC Token + if: github.repository == 'stainless-sdks/scan-documents-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/scan-documents-typescript' + env: + URL: https://pkg.stainless.com/s + AUTH: ${{ steps.github-oidc.outputs.github_token }} + SHA: ${{ github.sha }} + run: ./scripts/utils/upload-artifact.sh + test: + timeout-minutes: 10 + name: test + runs-on: ${{ github.repository == 'stainless-sdks/scan-documents-typescript' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} + steps: + - uses: actions/checkout@v4 + + - name: Set up Node + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: Bootstrap + run: ./scripts/bootstrap + + - name: Run tests + run: ./scripts/test diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d98d51a --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +.prism.log +node_modules +yarn-error.log +codegen.log +Brewfile.lock.json +dist +dist-deno +/*.tgz +.idea/ + diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..3548c5a --- /dev/null +++ b/.prettierignore @@ -0,0 +1,7 @@ +CHANGELOG.md +/ecosystem-tests/*/** +/node_modules +/deno + +# don't format tsc output, will break source maps +/dist diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 0000000..af75ada --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,7 @@ +{ + "arrowParens": "always", + "experimentalTernaries": true, + "printWidth": 110, + "singleQuote": true, + "trailingComma": "all" +} diff --git a/.stats.yml b/.stats.yml new file mode 100644 index 0000000..efeed00 --- /dev/null +++ b/.stats.yml @@ -0,0 +1,4 @@ +configured_endpoints: 17 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/scan-documents%2Fscan-documents-04f736d0a9ae5151fec360201288ee49dc02cc4f60adf1ff17c5e3a0bbb639b4.yml +openapi_spec_hash: e9d1be2b0eae296e605a9a79af48ab63 +config_hash: 51f73a6963f0ae992703d2d999576437 diff --git a/Brewfile b/Brewfile new file mode 100644 index 0000000..e4feee6 --- /dev/null +++ b/Brewfile @@ -0,0 +1 @@ +brew "node" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..ef88a64 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,93 @@ +## Setting up the environment + +This repository uses [`yarn@v1`](https://classic.yarnpkg.com/lang/en/docs/install). +Other package managers may work but are not officially supported for development. + +To set up the repository, run: + +```sh +$ yarn +$ yarn build +``` + +This will install all the required dependencies and build output files to `dist/`. + +## Modifying/Adding code + +Most of the SDK is generated code. Modifications to code will be persisted between generations, but may +result in merge conflicts between manual patches and changes from the generator. The generator will never +modify the contents of the `src/lib/` and `examples/` directories. + +## Adding and running examples + +All files in the `examples/` directory are not modified by the generator and can be freely edited or added to. + +```ts +// add an example to examples/.ts + +#!/usr/bin/env -S npm run tsn -T +… +``` + +```sh +$ chmod +x examples/.ts +# run the example against your api +$ yarn tsn -T examples/.ts +``` + +## Using the repository from source + +If you’d like to use the repository from source, you can either install from git or link to a cloned repository: + +To install via git: + +```sh +$ npm install git+ssh://git@github.com:stainless-sdks/scan-documents-typescript.git +``` + +Alternatively, to link a local copy of the repo: + +```sh +# Clone +$ git clone https://www.github.com/stainless-sdks/scan-documents-typescript +$ cd scan-documents-typescript + +# With yarn +$ yarn link +$ cd ../my-package +$ yarn link scan-documents + +# With pnpm +$ pnpm link --global +$ cd ../my-package +$ pnpm link -—global scan-documents +``` + +## Running tests + +Most tests require you to [set up a mock server](https://github.com/stoplightio/prism) against the OpenAPI spec to run the tests. + +```sh +$ npx prism mock path/to/your/openapi.yml +``` + +```sh +$ yarn run test +``` + +## Linting and formatting + +This repository uses [prettier](https://www.npmjs.com/package/prettier) and +[eslint](https://www.npmjs.com/package/eslint) to format the code in the repository. + +To lint: + +```sh +$ yarn lint +``` + +To format and fix all lint issues automatically: + +```sh +$ yarn fix +``` diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..f4534d7 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2025 Scan Documents + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md index e524dda..8ca2846 100644 --- a/README.md +++ b/README.md @@ -1 +1,411 @@ -# scan-documents-typescript \ No newline at end of file +# Scan Documents TypeScript API Library + +[![NPM version](https://img.shields.io/npm/v/scan-documents.svg)](https://npmjs.org/package/scan-documents) ![npm bundle size](https://img.shields.io/bundlephobia/minzip/scan-documents) + +This library provides convenient access to the Scan Documents REST API from server-side TypeScript or JavaScript. + +The full API of this library can be found in [api.md](api.md). + +It is generated with [Stainless](https://www.stainless.com/). + +## Installation + +```sh +npm install git+ssh://git@github.com:stainless-sdks/scan-documents-typescript.git +``` + +> [!NOTE] +> Once this package is [published to npm](https://app.stainless.com/docs/guides/publish), this will become: `npm install scan-documents` + +## Usage + +The full API of this library can be found in [api.md](api.md). + + +```js +import ScanDocuments from 'scan-documents'; + +const client = new ScanDocuments({ + apiKey: process.env['SCAN_DOCUMENTS_API_KEY'], // This is the default and can be omitted +}); + +async function main() { + const file = await client.files.upload({ file: fs.createReadStream('path/to/file'), name: 'REPLACE_ME' }); +} + +main(); +``` + +### Request & Response types + +This library includes TypeScript definitions for all request params and response fields. You may import and use them like so: + + +```ts +import ScanDocuments from 'scan-documents'; + +const client = new ScanDocuments({ + apiKey: process.env['SCAN_DOCUMENTS_API_KEY'], // This is the default and can be omitted +}); + +async function main() { + const params: ScanDocuments.FileUploadParams = { + file: fs.createReadStream('path/to/file'), + name: 'REPLACE_ME', + }; + const file: ScanDocuments.File = await client.files.upload(params); +} + +main(); +``` + +Documentation for each method, request param, and response field are available in docstrings and will appear on hover in most modern editors. + +## File uploads + +Request parameters that correspond to file uploads can be passed in many different forms: + +- `File` (or an object with the same structure) +- a `fetch` `Response` (or an object with the same structure) +- an `fs.ReadStream` +- the return value of our `toFile` helper + +```ts +import fs from 'fs'; +import ScanDocuments, { toFile } from 'scan-documents'; + +const client = new ScanDocuments(); + +// If you have access to Node `fs` we recommend using `fs.createReadStream()`: +await client.files.upload({ file: fs.createReadStream('/path/to/file'), name: 'File Name' }); + +// Or if you have the web `File` API you can pass a `File` instance: +await client.files.upload({ file: new File(['my bytes'], 'file'), name: 'File Name' }); + +// You can also pass a `fetch` `Response`: +await client.files.upload({ file: await fetch('https://somesite/file'), name: 'File Name' }); + +// Finally, if none of the above are convenient, you can use our `toFile` helper: +await client.files.upload({ file: await toFile(Buffer.from('my bytes'), 'file'), name: 'File Name' }); +await client.files.upload({ file: await toFile(new Uint8Array([0, 1, 2]), 'file'), name: 'File Name' }); +``` + +## Handling errors + +When the library is unable to connect to the API, +or if the API returns a non-success status code (i.e., 4xx or 5xx response), +a subclass of `APIError` will be thrown: + + +```ts +async function main() { + const file = await client.files + .upload({ file: fs.createReadStream('path/to/file'), name: 'REPLACE_ME' }) + .catch(async (err) => { + if (err instanceof ScanDocuments.APIError) { + console.log(err.status); // 400 + console.log(err.name); // BadRequestError + console.log(err.headers); // {server: 'nginx', ...} + } else { + throw err; + } + }); +} + +main(); +``` + +Error codes are as follows: + +| Status Code | Error Type | +| ----------- | -------------------------- | +| 400 | `BadRequestError` | +| 401 | `AuthenticationError` | +| 403 | `PermissionDeniedError` | +| 404 | `NotFoundError` | +| 422 | `UnprocessableEntityError` | +| 429 | `RateLimitError` | +| >=500 | `InternalServerError` | +| N/A | `APIConnectionError` | + +### Retries + +Certain errors will be automatically retried 2 times by default, with a short exponential backoff. +Connection errors (for example, due to a network connectivity problem), 408 Request Timeout, 409 Conflict, +429 Rate Limit, and >=500 Internal errors will all be retried by default. + +You can use the `maxRetries` option to configure or disable this: + + +```js +// Configure the default for all requests: +const client = new ScanDocuments({ + maxRetries: 0, // default is 2 +}); + +// Or, configure per-request: +await client.files.upload({ file: fs.createReadStream('path/to/file'), name: 'REPLACE_ME' }, { + maxRetries: 5, +}); +``` + +### Timeouts + +Requests time out after 1 minute by default. You can configure this with a `timeout` option: + + +```ts +// Configure the default for all requests: +const client = new ScanDocuments({ + timeout: 20 * 1000, // 20 seconds (default is 1 minute) +}); + +// Override per-request: +await client.files.upload({ file: fs.createReadStream('path/to/file'), name: 'REPLACE_ME' }, { + timeout: 5 * 1000, +}); +``` + +On timeout, an `APIConnectionTimeoutError` is thrown. + +Note that requests which time out will be [retried twice by default](#retries). + +## Advanced Usage + +### 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 +const client = new ScanDocuments(); + +const response = await client.files + .upload({ file: fs.createReadStream('path/to/file'), name: 'REPLACE_ME' }) + .asResponse(); +console.log(response.headers.get('X-My-Header')); +console.log(response.statusText); // access the underlying Response object + +const { data: file, response: raw } = await client.files + .upload({ file: fs.createReadStream('path/to/file'), name: 'REPLACE_ME' }) + .withResponse(); +console.log(raw.headers.get('X-My-Header')); +console.log(file); +``` + +### 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 `SCAN_DOCUMENTS_LOG` environment variable +2. Using the `logLevel` client option (overrides the environment variable if set) + +```ts +import ScanDocuments from 'scan-documents'; + +const client = new ScanDocuments({ + 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 ScanDocuments from 'scan-documents'; +import pino from 'pino'; + +const logger = pino(); + +const client = new ScanDocuments({ + logger: logger.child({ name: 'ScanDocuments' }), + 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 +endpoints, params, or response properties, the library can still be used. + +#### Undocumented endpoints + +To make requests to undocumented endpoints, you can use `client.get`, `client.post`, and other HTTP verbs. +Options on the client, such as retries, will be respected when making these requests. + +```ts +await client.post('/some/path', { + body: { some_prop: 'foo' }, + query: { some_query_arg: 'bar' }, +}); +``` + +#### Undocumented request params + +To make requests using undocumented parameters, you may use `// @ts-expect-error` on the undocumented +parameter. This library doesn't validate at runtime that the request matches the type, so any extra values you +send will be sent as-is. + +```ts +client.foo.create({ + foo: 'my_param', + bar: 12, + // @ts-expect-error baz is not yet public + baz: 'undocumented option', +}); +``` + +For requests with the `GET` verb, any extra params will be in the query, all other requests will send the +extra param in the body. + +If you want to explicitly send an extra argument, you can do so with the `query`, `body`, and `headers` request +options. + +#### Undocumented response properties + +To access undocumented response properties, you may access the response object with `// @ts-expect-error` on +the response object, or cast the response object to the requisite type. Like the request params, we do not +validate or strip extra properties from the response from the API. + +### Customizing the fetch client + +By default, this library expects a global `fetch` function is defined. + +If you want to use a different `fetch` function, you can either polyfill the global: + +```ts +import fetch from 'my-fetch'; + +globalThis.fetch = fetch; +``` + +Or pass it to the client: + +```ts +import ScanDocuments from 'scan-documents'; +import fetch from 'my-fetch'; + +const client = new ScanDocuments({ fetch }); +``` + +### Fetch options + +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 ScanDocuments from 'scan-documents'; + +const client = new ScanDocuments({ + fetchOptions: { + // `RequestInit` options + }, +}); +``` + +#### Configuring proxies + +To modify proxy behavior, you can provide custom `fetchOptions` that add runtime-specific proxy +options to requests: + + **Node** [[docs](https://github.com/nodejs/undici/blob/main/docs/docs/api/ProxyAgent.md#example---proxyagent-with-fetch)] + +```ts +import ScanDocuments from 'scan-documents'; +import * as undici from 'undici'; + +const proxyAgent = new undici.ProxyAgent('http://localhost:8888'); +const client = new ScanDocuments({ + fetchOptions: { + dispatcher: proxyAgent, + }, +}); +``` + + **Bun** [[docs](https://bun.sh/guides/http/proxy)] + +```ts +import ScanDocuments from 'scan-documents'; + +const client = new ScanDocuments({ + fetchOptions: { + proxy: 'http://localhost:8888', + }, +}); +``` + + **Deno** [[docs](https://docs.deno.com/api/deno/~/Deno.createHttpClient)] + +```ts +import ScanDocuments from 'npm:scan-documents'; + +const httpClient = Deno.createHttpClient({ proxy: { url: 'http://localhost:8888' } }); +const client = new ScanDocuments({ + fetchOptions: { + client: httpClient, + }, +}); +``` + +## Frequently Asked Questions + +## Semantic versioning + +This package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions: + +1. Changes that only affect static types, without breaking runtime behavior. +2. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals.)_ +3. Changes that we do not expect to impact the vast majority of users in practice. + +We take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience. + +We are keen for your feedback; please open an [issue](https://www.github.com/stainless-sdks/scan-documents-typescript/issues) with questions, bugs, or suggestions. + +## Requirements + +TypeScript >= 4.9 is supported. + +The following runtimes are supported: + +- Web browsers (Up-to-date Chrome, Firefox, Safari, Edge, and more) +- 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. +- Vercel Edge Runtime. +- Jest 28 or greater with the `"node"` environment (`"jsdom"` is not supported at this time). +- Nitro v2.6 or greater. + +Note that React Native is not supported at this time. + +If you are interested in other runtime environments, please open or upvote an issue on GitHub. + +## Contributing + +See [the contributing documentation](./CONTRIBUTING.md). diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..0b35be9 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,23 @@ +# Security Policy + +## Reporting Security Issues + +This SDK is generated by [Stainless Software Inc](http://stainless.com). Stainless takes security seriously, and encourages you to report any security vulnerability promptly so that appropriate action can be taken. + +To report a security issue, please contact the Stainless team at security@stainless.com. + +## Responsible Disclosure + +We appreciate the efforts of security researchers and individuals who help us maintain the security of +SDKs we generate. If you believe you have found a security vulnerability, please adhere to responsible +disclosure practices by allowing us a reasonable amount of time to investigate and address the issue +before making any information public. + +## Reporting Non-SDK Related Security Issues + +If you encounter security issues that are not directly related to SDKs but pertain to the services +or products provided by Scan Documents please follow the respective company's security reporting guidelines. + +--- + +Thank you for helping us keep the SDKs and systems they interact with secure. diff --git a/api.md b/api.md new file mode 100644 index 0000000..ea8198c --- /dev/null +++ b/api.md @@ -0,0 +1,77 @@ +# Files + +Types: + +- File +- FileListResponse + +Methods: + +- client.files.retrieve(id) -> File +- client.files.list({ ...params }) -> FileListResponse +- client.files.delete(id) -> void +- client.files.download(id) -> Response +- client.files.upload({ ...params }) -> File + +# Tasks + +Types: + +- TaskResponse +- TaskListResponse + +Methods: + +- client.tasks.retrieve(id) -> TaskResponse +- client.tasks.list({ ...params }) -> TaskListResponse + +# Events + +Types: + +- EventListResponse + +Methods: + +- client.events.list({ ...params }) -> EventListResponse + +# ImageOperations + +Types: + +- ApplyEffectResponse +- BoundingBox +- ConvertRequest +- ConvertResponse +- CoordinatesItem +- DetectDocumentsResponse +- ExtractTextRequest +- ExtractTextResponse +- ImageFromTaskResponse +- WarpRequest +- WarpResponse + +Methods: + +- client.imageOperations.applyEffect({ ...params }) -> ApplyEffectResponse +- client.imageOperations.convert({ ...params }) -> ConvertResponse +- client.imageOperations.detectDocuments({ ...params }) -> DetectDocumentsResponse +- client.imageOperations.extractText({ ...params }) -> ExtractTextResponse +- client.imageOperations.warp({ ...params }) -> WarpResponse + +# PdfOperations + +Types: + +- DocumentFromTask +- ExtractPages +- Merge +- Render +- Split + +Methods: + +- client.pdfOperations.extractPages({ ...params }) -> ExtractPages +- client.pdfOperations.merge({ ...params }) -> Merge +- client.pdfOperations.render({ ...params }) -> Render +- client.pdfOperations.split({ ...params }) -> Split diff --git a/bin/publish-npm b/bin/publish-npm new file mode 100644 index 0000000..4c21181 --- /dev/null +++ b/bin/publish-npm @@ -0,0 +1,25 @@ +#!/usr/bin/env bash + +set -eux + +npm config set '//registry.npmjs.org/:_authToken' "$NPM_TOKEN" + +# Build the project +yarn build + +# Navigate to the dist directory +cd dist + +# Get the version from package.json +VERSION="$(node -p "require('./package.json').version")" + +# Extract the pre-release tag if it exists +if [[ "$VERSION" =~ -([a-zA-Z]+) ]]; then + # Extract the part before any dot in the pre-release identifier + TAG="${BASH_REMATCH[1]}" +else + TAG="latest" +fi + +# Publish with the appropriate tag +yarn publish --access public --tag "$TAG" diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000..699a035 --- /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/**'], + 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: '^scan-documents(/.*)?', + message: 'Use a relative import, not a package import.', + }, + ], + }, + ], + }, + }, + { + files: ['tests/**', 'examples/**'], + rules: { + 'no-restricted-imports': 'off', + }, + }, +); diff --git a/examples/.keep b/examples/.keep new file mode 100644 index 0000000..0651c89 --- /dev/null +++ b/examples/.keep @@ -0,0 +1,4 @@ +File generated from our OpenAPI spec by Stainless. + +This directory can be used to store example files demonstrating usage of this SDK. +It is ignored by Stainless code generation and its content (other than this keep file) won't be touched. diff --git a/jest.config.ts b/jest.config.ts new file mode 100644 index 0000000..81d36c7 --- /dev/null +++ b/jest.config.ts @@ -0,0 +1,22 @@ +import type { JestConfigWithTsJest } from 'ts-jest'; + +const config: JestConfigWithTsJest = { + preset: 'ts-jest/presets/default-esm', + testEnvironment: 'node', + transform: { + '^.+\\.(t|j)sx?$': ['@swc/jest', { sourceMaps: 'inline' }], + }, + moduleNameMapper: { + '^scan-documents$': '/src/index.ts', + '^scan-documents/(.*)$': '/src/$1', + }, + modulePathIgnorePatterns: [ + '/ecosystem-tests/', + '/dist/', + '/deno/', + '/deno_tests/', + ], + testPathIgnorePatterns: ['scripts'], +}; + +export default config; diff --git a/package.json b/package.json new file mode 100644 index 0000000..2e5b442 --- /dev/null +++ b/package.json @@ -0,0 +1,72 @@ +{ + "name": "scan-documents", + "version": "0.0.1-alpha.0", + "description": "The official TypeScript library for the Scan Documents API", + "author": "Scan Documents <>", + "types": "dist/index.d.ts", + "main": "dist/index.js", + "type": "commonjs", + "repository": "github:stainless-sdks/scan-documents-typescript", + "license": "Apache-2.0", + "packageManager": "yarn@1.22.22", + "files": [ + "**/*" + ], + "private": false, + "scripts": { + "test": "./scripts/test", + "build": "./scripts/build", + "prepublishOnly": "echo 'to publish, run yarn build && (cd dist; yarn publish)' && exit 1", + "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": {}, + "devDependencies": { + "@arethetypeswrong/cli": "^0.17.0", + "@swc/core": "^1.3.102", + "@swc/jest": "^0.2.29", + "@types/jest": "^29.4.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", + "iconv-lite": "^0.6.3", + "jest": "^29.4.0", + "prettier": "^3.0.0", + "publint": "^0.2.12", + "ts-jest": "^29.1.0", + "ts-node": "^10.5.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": "5.8.3" + }, + "resolutions": { + "synckit": "0.8.8" + }, + "imports": { + "scan-documents": ".", + "scan-documents/*": "./src/*" + }, + "exports": { + ".": { + "import": "./dist/index.mjs", + "require": "./dist/index.js" + }, + "./*.mjs": { + "default": "./dist/*.mjs" + }, + "./*.js": { + "default": "./dist/*.js" + }, + "./*": { + "import": "./dist/*.mjs", + "require": "./dist/*.js" + } + } +} diff --git a/scripts/bootstrap b/scripts/bootstrap new file mode 100755 index 0000000..0af58e2 --- /dev/null +++ b/scripts/bootstrap @@ -0,0 +1,18 @@ +#!/usr/bin/env bash + +set -e + +cd "$(dirname "$0")/.." + +if [ -f "Brewfile" ] && [ "$(uname -s)" = "Darwin" ] && [ "$SKIP_BREW" != "1" ]; then + brew bundle check >/dev/null 2>&1 || { + echo "==> Installing Homebrew dependencies…" + brew bundle + } +fi + +echo "==> Installing Node dependencies…" + +PACKAGE_MANAGER=$(command -v yarn >/dev/null 2>&1 && echo "yarn" || echo "npm") + +$PACKAGE_MANAGER install diff --git a/scripts/build b/scripts/build new file mode 100755 index 0000000..6fece32 --- /dev/null +++ b/scripts/build @@ -0,0 +1,53 @@ +#!/usr/bin/env bash + +set -exuo pipefail + +cd "$(dirname "$0")/.." + +node scripts/utils/check-version.cjs + +# Build into dist and will publish the package from there, +# so that src/resources/foo.ts becomes /resources/foo.js +# This way importing from `"scan-documents/resources/foo"` works +# even with `"moduleResolution": "node"` + +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 +for file in LICENSE CHANGELOG.md; do + if [ -e "${file}" ]; then cp "${file}" dist; fi +done +if [ -e "bin/cli" ]; then + 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 +# 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 +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 + +# make sure that nothing crashes when we require the output CJS or +# import the output ESM +(cd dist && node -e 'require("scan-documents")') +(cd dist && node -e 'import("scan-documents")' --input-type=module) + +if [ -e ./scripts/build-deno ] +then + ./scripts/build-deno +fi diff --git a/scripts/format b/scripts/format new file mode 100755 index 0000000..7a75640 --- /dev/null +++ b/scripts/format @@ -0,0 +1,12 @@ +#!/usr/bin/env bash + +set -e + +cd "$(dirname "$0")/.." + +echo "==> Running eslint --fix" +./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 new file mode 100755 index 0000000..3ffb78a --- /dev/null +++ b/scripts/lint @@ -0,0 +1,21 @@ +#!/usr/bin/env bash + +set -e + +cd "$(dirname "$0")/.." + +echo "==> Running eslint" +./node_modules/.bin/eslint . + +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/mock b/scripts/mock new file mode 100755 index 0000000..d2814ae --- /dev/null +++ b/scripts/mock @@ -0,0 +1,41 @@ +#!/usr/bin/env bash + +set -e + +cd "$(dirname "$0")/.." + +if [[ -n "$1" && "$1" != '--'* ]]; then + URL="$1" + shift +else + URL="$(grep 'openapi_spec_url' .stats.yml | cut -d' ' -f2)" +fi + +# Check if the URL is empty +if [ -z "$URL" ]; then + echo "Error: No OpenAPI spec path/url provided or found in .stats.yml" + exit 1 +fi + +echo "==> Starting mock server with URL ${URL}" + +# Run prism mock on the given spec +if [ "$1" == "--daemon" ]; then + npm exec --package=@stainless-api/prism-cli@5.8.5 -- prism mock "$URL" &> .prism.log & + + # Wait for server to come online + echo -n "Waiting for server" + while ! grep -q "✖ fatal\|Prism is listening" ".prism.log" ; do + echo -n "." + sleep 0.1 + done + + if grep -q "✖ fatal" ".prism.log"; then + cat .prism.log + exit 1 + fi + + echo +else + npm exec --package=@stainless-api/prism-cli@5.8.5 -- prism mock "$URL" +fi diff --git a/scripts/test b/scripts/test new file mode 100755 index 0000000..2049e31 --- /dev/null +++ b/scripts/test @@ -0,0 +1,56 @@ +#!/usr/bin/env bash + +set -e + +cd "$(dirname "$0")/.." + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[0;33m' +NC='\033[0m' # No Color + +function prism_is_running() { + curl --silent "http://localhost:4010" >/dev/null 2>&1 +} + +kill_server_on_port() { + pids=$(lsof -t -i tcp:"$1" || echo "") + if [ "$pids" != "" ]; then + kill "$pids" + echo "Stopped $pids." + fi +} + +function is_overriding_api_base_url() { + [ -n "$TEST_API_BASE_URL" ] +} + +if ! is_overriding_api_base_url && ! prism_is_running ; then + # When we exit this script, make sure to kill the background mock server process + trap 'kill_server_on_port 4010' EXIT + + # Start the dev server + ./scripts/mock --daemon +fi + +if is_overriding_api_base_url ; then + echo -e "${GREEN}✔ Running tests against ${TEST_API_BASE_URL}${NC}" + echo +elif ! prism_is_running ; then + echo -e "${RED}ERROR:${NC} The test suite will not run without a mock Prism server" + echo -e "running against your OpenAPI spec." + echo + echo -e "To run the server, pass in the path or url of your OpenAPI" + echo -e "spec to the prism command:" + echo + echo -e " \$ ${YELLOW}npm exec --package=@stoplight/prism-cli@~5.3.2 -- prism mock path/to/your.openapi.yml${NC}" + echo + + exit 1 +else + echo -e "${GREEN}✔ Mock prism server is running with your OpenAPI spec${NC}" + echo +fi + +echo "==> Running tests" +./node_modules/.bin/jest "$@" diff --git a/scripts/utils/attw-report.cjs b/scripts/utils/attw-report.cjs new file mode 100644 index 0000000..b3477c0 --- /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/check-is-in-git-install.sh b/scripts/utils/check-is-in-git-install.sh new file mode 100755 index 0000000..1354eb4 --- /dev/null +++ b/scripts/utils/check-is-in-git-install.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +# Check if you happen to call prepare for a repository that's already in node_modules. +[ "$(basename "$(dirname "$PWD")")" = 'node_modules' ] || +# The name of the containing directory that 'npm` uses, which looks like +# $HOME/.npm/_cacache/git-cloneXXXXXX +[ "$(basename "$(dirname "$PWD")")" = 'tmp' ] || +# The name of the containing directory that 'yarn` uses, which looks like +# $(yarn cache dir)/.tmp/XXXXX +[ "$(basename "$(dirname "$PWD")")" = '.tmp' ] diff --git a/scripts/utils/check-version.cjs b/scripts/utils/check-version.cjs new file mode 100644 index 0000000..86c56df --- /dev/null +++ b/scripts/utils/check-version.cjs @@ -0,0 +1,20 @@ +const fs = require('fs'); +const path = require('path'); + +const main = () => { + const pkg = require('../../package.json'); + const version = pkg['version']; + if (!version) throw 'The version property is not set in the package.json file'; + if (typeof version !== 'string') { + throw `Unexpected type for the package.json version field; got ${typeof version}, expected string`; + } + + const versionFile = path.resolve(__dirname, '..', '..', 'src', 'version.ts'); + const contents = fs.readFileSync(versionFile, 'utf8'); + const output = contents.replace(/(export const VERSION = ')(.*)(')/g, `$1${version}$3`); + fs.writeFileSync(versionFile, output); +}; + +if (require.main === module) { + main(); +} diff --git a/scripts/utils/fix-index-exports.cjs b/scripts/utils/fix-index-exports.cjs new file mode 100644 index 0000000..e5e10b3 --- /dev/null +++ b/scripts/utils/fix-index-exports.cjs @@ -0,0 +1,17 @@ +const fs = require('fs'); +const path = require('path'); + +const indexJs = + process.env['DIST_PATH'] ? + path.resolve(process.env['DIST_PATH'], 'index.js') + : path.resolve(__dirname, '..', '..', 'dist', 'index.js'); + +let before = fs.readFileSync(indexJs, 'utf8'); +let after = before.replace( + /^(\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/git-swap.sh b/scripts/utils/git-swap.sh new file mode 100755 index 0000000..79d1888 --- /dev/null +++ b/scripts/utils/git-swap.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -exuo pipefail +# the package is published to NPM from ./dist +# we want the final file structure for git installs to match the npm installs, so we + +# delete everything except ./dist and ./node_modules +find . -maxdepth 1 -mindepth 1 ! -name 'dist' ! -name 'node_modules' -exec rm -rf '{}' + + +# move everything from ./dist to . +mv dist/* . + +# delete the now-empty ./dist +rmdir dist diff --git a/scripts/utils/make-dist-package-json.cjs b/scripts/utils/make-dist-package-json.cjs new file mode 100644 index 0000000..7c24f56 --- /dev/null +++ b/scripts/utils/make-dist-package-json.cjs @@ -0,0 +1,21 @@ +const pkgJson = require(process.env['PKG_JSON_PATH'] || '../../package.json'); + +function processExportMap(m) { + for (const key in m) { + const value = m[key]; + if (typeof value === 'string') m[key] = value.replace(/^\.\/dist\//, './'); + else processExportMap(value); + } +} +processExportMap(pkgJson.exports); + +for (const key of ['types', 'main', 'module']) { + if (typeof pkgJson[key] === 'string') pkgJson[key] = pkgJson[key].replace(/^(\.\/)?dist\//, './'); +} + +delete pkgJson.devDependencies; +delete pkgJson.scripts.prepack; +delete pkgJson.scripts.prepublishOnly; +delete pkgJson.scripts.prepare; + +console.log(JSON.stringify(pkgJson, null, 2)); diff --git a/scripts/utils/postprocess-files.cjs b/scripts/utils/postprocess-files.cjs new file mode 100644 index 0000000..deae575 --- /dev/null +++ b/scripts/utils/postprocess-files.cjs @@ -0,0 +1,94 @@ +// @ts-check +const fs = require('fs'); +const path = require('path'); + +const distDir = + process.env['DIST_PATH'] ? + path.resolve(process.env['DIST_PATH']) + : path.resolve(__dirname, '..', '..', 'dist'); + +async function* walk(dir) { + for await (const d of await fs.promises.opendir(dir)) { + const entry = path.join(dir, d.name); + if (d.isDirectory()) yield* walk(entry); + else if (d.isFile()) yield entry; + } +} + +async function postprocess() { + for await (const file of walk(distDir)) { + if (!/(\.d)?[cm]?ts$/.test(file)) continue; + + const code = await fs.promises.readFile(file, 'utf8'); + + // strip out lib="dom", types="node", and types="react" references; these + // are needed at build time, but would pollute the user's TS environment + const transformed = code.replace( + /^ *\/\/\/ * ' '.repeat(match.length - 1) + '\n', + ); + + if (transformed !== code) { + 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 new file mode 100755 index 0000000..d89492a --- /dev/null +++ b/scripts/utils/upload-artifact.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +set -exuo pipefail + +RESPONSE=$(curl -X POST "$URL" \ + -H "Authorization: Bearer $AUTH" \ + -H "Content-Type: application/json") + +SIGNED_URL=$(echo "$RESPONSE" | jq -r '.url') + +if [[ "$SIGNED_URL" == "null" ]]; then + echo -e "\033[31mFailed to get signed URL.\033[0m" + exit 1 +fi + +UPLOAD_RESPONSE=$(tar -cz dist | curl -v -X PUT \ + -H "Content-Type: application/gzip" \ + --data-binary @- "$SIGNED_URL" 2>&1) + +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/scan-documents-typescript/$SHA'\033[0m" +else + echo -e "\033[31mFailed to upload artifact.\033[0m" + exit 1 +fi diff --git a/src/api-promise.ts b/src/api-promise.ts new file mode 100644 index 0000000..8c775ee --- /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/client.ts b/src/client.ts new file mode 100644 index 0000000..4d65f4b --- /dev/null +++ b/src/client.ts @@ -0,0 +1,794 @@ +// 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 { VERSION } from './version'; +import * as Errors from './core/error'; +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 { HeadersLike, NullableHeaders, buildHeaders } from './internal/headers'; +import { FinalRequestOptions, RequestOptions } from './internal/request-options'; +import { EventListParams, EventListResponse, Events } from './resources/events'; +import { File, FileListParams, FileListResponse, FileUploadParams, Files } from './resources/files'; +import { + ApplyEffectResponse, + BoundingBox, + ConvertRequest, + ConvertResponse, + CoordinatesItem, + DetectDocumentsResponse, + ExtractTextRequest, + ExtractTextResponse, + ImageFromTaskResponse, + ImageOperationApplyEffectParams, + ImageOperationConvertParams, + ImageOperationDetectDocumentsParams, + ImageOperationExtractTextParams, + ImageOperationWarpParams, + ImageOperations, + WarpRequest, + WarpResponse, +} from './resources/image-operations'; +import { + DocumentFromTask, + ExtractPages, + Merge, + PdfOperationExtractPagesParams, + PdfOperationMergeParams, + PdfOperationRenderParams, + PdfOperationSplitParams, + PdfOperations, + Render, + Split, +} from './resources/pdf-operations'; +import { TaskListParams, TaskListResponse, TaskResponse, Tasks } from './resources/tasks'; +import { readEnv } from './internal/utils/env'; +import { formatRequestDetails, loggerFor } from './internal/utils/log'; +import { isEmptyObj } from './internal/utils/values'; + +export interface ClientOptions { + /** + * API Key for authentication + */ + apiKey?: string | undefined; + + /** + * Override the default base URL for the API, e.g., "https://api.example.com/v2/" + * + * Defaults to process.env['SCAN_DOCUMENTS_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; + + /** + * Set the log level. + * + * Defaults to process.env['SCAN_DOCUMENTS_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 Scan Documents API. + */ +export class ScanDocuments { + apiKey: string; + + 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 Scan Documents API. + * + * @param {string | undefined} [opts.apiKey=process.env['SCAN_DOCUMENTS_API_KEY'] ?? undefined] + * @param {string} [opts.baseURL=process.env['SCAN_DOCUMENTS_BASE_URL'] ?? https://api.scan-documents.com] - Override the default base URL for the API. + * @param {number} [opts.timeout=1 minute] - 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. + */ + constructor({ + baseURL = readEnv('SCAN_DOCUMENTS_BASE_URL'), + apiKey = readEnv('SCAN_DOCUMENTS_API_KEY'), + ...opts + }: ClientOptions = {}) { + if (apiKey === undefined) { + throw new Errors.ScanDocumentsError( + "The SCAN_DOCUMENTS_API_KEY environment variable is missing or empty; either provide it, or instantiate the ScanDocuments client with an apiKey option, like new ScanDocuments({ apiKey: 'My API Key' }).", + ); + } + + const options: ClientOptions = { + apiKey, + ...opts, + baseURL: baseURL || `https://api.scan-documents.com`, + }; + + this.baseURL = options.baseURL!; + this.timeout = options.timeout ?? ScanDocuments.DEFAULT_TIMEOUT /* 1 minute */; + 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('SCAN_DOCUMENTS_LOG'), "process.env['SCAN_DOCUMENTS_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; + } + + /** + * 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, + ...options, + }); + } + + protected defaultQuery(): Record | undefined { + return this._options.defaultQuery; + } + + protected validateHeaders({ values, nulls }: NullableHeaders) { + return; + } + + protected authHeaders(opts: FinalRequestOptions): NullableHeaders | undefined { + return buildHeaders([{ 'x-api-key': this.apiKey }]); + } + + /** + * Basic re-implementation of `qs.stringify` for primitive types. + */ + 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 Errors.ScanDocumentsError( + `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('&'); + } + + 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 responseInfo = `[${requestLogID}${retryLogStr}] ${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 }; + } + + 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(), + }, + 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 ScanDocuments = this; + static DEFAULT_TIMEOUT = 60000; // 1 minute + + static ScanDocumentsError = Errors.ScanDocumentsError; + 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; + + files: API.Files = new API.Files(this); + tasks: API.Tasks = new API.Tasks(this); + events: API.Events = new API.Events(this); + imageOperations: API.ImageOperations = new API.ImageOperations(this); + pdfOperations: API.PdfOperations = new API.PdfOperations(this); +} +ScanDocuments.Files = Files; +ScanDocuments.Tasks = Tasks; +ScanDocuments.Events = Events; +ScanDocuments.ImageOperations = ImageOperations; +ScanDocuments.PdfOperations = PdfOperations; +export declare namespace ScanDocuments { + export type RequestOptions = Opts.RequestOptions; + + export { + Files as Files, + type File as File, + type FileListResponse as FileListResponse, + type FileListParams as FileListParams, + type FileUploadParams as FileUploadParams, + }; + + export { + Tasks as Tasks, + type TaskResponse as TaskResponse, + type TaskListResponse as TaskListResponse, + type TaskListParams as TaskListParams, + }; + + export { + Events as Events, + type EventListResponse as EventListResponse, + type EventListParams as EventListParams, + }; + + export { + ImageOperations as ImageOperations, + type ApplyEffectResponse as ApplyEffectResponse, + type BoundingBox as BoundingBox, + type ConvertRequest as ConvertRequest, + type ConvertResponse as ConvertResponse, + type CoordinatesItem as CoordinatesItem, + type DetectDocumentsResponse as DetectDocumentsResponse, + type ExtractTextRequest as ExtractTextRequest, + type ExtractTextResponse as ExtractTextResponse, + type ImageFromTaskResponse as ImageFromTaskResponse, + type WarpRequest as WarpRequest, + type WarpResponse as WarpResponse, + type ImageOperationApplyEffectParams as ImageOperationApplyEffectParams, + type ImageOperationConvertParams as ImageOperationConvertParams, + type ImageOperationDetectDocumentsParams as ImageOperationDetectDocumentsParams, + type ImageOperationExtractTextParams as ImageOperationExtractTextParams, + type ImageOperationWarpParams as ImageOperationWarpParams, + }; + + export { + PdfOperations as PdfOperations, + type DocumentFromTask as DocumentFromTask, + type ExtractPages as ExtractPages, + type Merge as Merge, + type Render as Render, + type Split as Split, + type PdfOperationExtractPagesParams as PdfOperationExtractPagesParams, + type PdfOperationMergeParams as PdfOperationMergeParams, + type PdfOperationRenderParams as PdfOperationRenderParams, + type PdfOperationSplitParams as PdfOperationSplitParams, + }; +} diff --git a/src/core/README.md b/src/core/README.md new file mode 100644 index 0000000..485fce8 --- /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 0000000..e324ea4 --- /dev/null +++ b/src/core/api-promise.ts @@ -0,0 +1,92 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { type ScanDocuments } from '../client'; + +import { type PromiseOrValue } from '../internal/types'; +import { APIResponseProps, defaultParseResponse } 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: ScanDocuments; + + constructor( + client: ScanDocuments, + private responsePromise: Promise, + private parseResponse: ( + client: ScanDocuments, + 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) => + transform(await this.parseResponse(client, props), props), + ); + } + + /** + * 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 and the raw `Response` instance. + * + * 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 }> { + const [data, response] = await Promise.all([this.parse(), this.asResponse()]); + return { data, response }; + } + + private parse(): Promise { + if (!this.parsedPromise) { + this.parsedPromise = this.responsePromise.then((data) => this.parseResponse(this.#client, data)); + } + return this.parsedPromise; + } + + override then( + onfulfilled?: ((value: T) => 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 { + 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 0000000..e8484e8 --- /dev/null +++ b/src/core/error.ts @@ -0,0 +1,130 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { castToError } from '../internal/errors'; + +export class ScanDocumentsError extends Error {} + +export class APIError< + TStatus extends number | undefined = number | undefined, + THeaders extends Headers | undefined = Headers | undefined, + TError extends Object | undefined = Object | undefined, +> extends ScanDocumentsError { + /** 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; + + constructor(status: TStatus, error: TError, message: string | undefined, headers: THeaders) { + super(`${APIError.makeMessage(status, error, message)}`); + this.status = status; + this.headers = headers; + this.error = error; + } + + 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; + + 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 {} diff --git a/src/core/resource.ts b/src/core/resource.ts new file mode 100644 index 0000000..4762be3 --- /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 { ScanDocuments } from '../client'; + +export class APIResource { + protected _client: ScanDocuments; + + constructor(client: ScanDocuments) { + this._client = client; + } +} diff --git a/src/core/uploads.ts b/src/core/uploads.ts new file mode 100644 index 0000000..2882ca6 --- /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 new file mode 100644 index 0000000..fc55f46 --- /dev/null +++ b/src/error.ts @@ -0,0 +1,2 @@ +/** @deprecated Import from ./core/error instead */ +export * from './core/error'; diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..36c6177 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,22 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export { ScanDocuments as default } from './client'; + +export { type Uploadable, toFile } from './core/uploads'; +export { APIPromise } from './core/api-promise'; +export { ScanDocuments, type ClientOptions } from './client'; +export { + ScanDocumentsError, + APIError, + APIConnectionError, + APIConnectionTimeoutError, + APIUserAbortError, + NotFoundError, + ConflictError, + RateLimitError, + BadRequestError, + AuthenticationError, + InternalServerError, + PermissionDeniedError, + UnprocessableEntityError, +} from './core/error'; diff --git a/src/internal/README.md b/src/internal/README.md new file mode 100644 index 0000000..3ef5a25 --- /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 0000000..c23d3bd --- /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/detect-platform.ts b/src/internal/detect-platform.ts new file mode 100644 index 0000000..c5e273b --- /dev/null +++ b/src/internal/detect-platform.ts @@ -0,0 +1,196 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { VERSION } from '../version'; + +export const isRunningInBrowser = () => { + return ( + // @ts-ignore + typeof window !== 'undefined' && + // @ts-ignore + typeof window.document !== 'undefined' && + // @ts-ignore + typeof navigator !== 'undefined' + ); +}; + +type DetectedPlatform = 'deno' | 'node' | 'edge' | 'unknown'; + +/** + * Note this does not detect 'browser'; for that, use getBrowserInfo(). + */ +function getDetectedPlatform(): DetectedPlatform { + if (typeof Deno !== 'undefined' && Deno.build != null) { + return 'deno'; + } + if (typeof EdgeRuntime !== 'undefined') { + return 'edge'; + } + if ( + Object.prototype.toString.call( + typeof (globalThis as any).process !== 'undefined' ? (globalThis as any).process : 0, + ) === '[object process]' + ) { + return 'node'; + } + return 'unknown'; +} + +declare const Deno: any; +declare const EdgeRuntime: any; +type Arch = 'x32' | 'x64' | 'arm' | 'arm64' | `other:${string}` | 'unknown'; +type PlatformName = + | 'MacOS' + | 'Linux' + | 'Windows' + | 'FreeBSD' + | 'OpenBSD' + | 'iOS' + | 'Android' + | `Other:${string}` + | 'Unknown'; +type Browser = 'ie' | 'edge' | 'chrome' | 'firefox' | 'safari'; +type PlatformProperties = { + 'X-Stainless-Lang': 'js'; + 'X-Stainless-Package-Version': string; + 'X-Stainless-OS': PlatformName; + 'X-Stainless-Arch': Arch; + 'X-Stainless-Runtime': 'node' | 'deno' | 'edge' | `browser:${Browser}` | 'unknown'; + 'X-Stainless-Runtime-Version': string; +}; +const getPlatformProperties = (): PlatformProperties => { + const detectedPlatform = getDetectedPlatform(); + if (detectedPlatform === 'deno') { + return { + 'X-Stainless-Lang': 'js', + 'X-Stainless-Package-Version': VERSION, + 'X-Stainless-OS': normalizePlatform(Deno.build.os), + 'X-Stainless-Arch': normalizeArch(Deno.build.arch), + 'X-Stainless-Runtime': 'deno', + 'X-Stainless-Runtime-Version': + typeof Deno.version === 'string' ? Deno.version : Deno.version?.deno ?? 'unknown', + }; + } + if (typeof EdgeRuntime !== 'undefined') { + return { + 'X-Stainless-Lang': 'js', + 'X-Stainless-Package-Version': VERSION, + 'X-Stainless-OS': 'Unknown', + 'X-Stainless-Arch': `other:${EdgeRuntime}`, + 'X-Stainless-Runtime': 'edge', + 'X-Stainless-Runtime-Version': (globalThis as any).process.version, + }; + } + // Check if Node.js + if (detectedPlatform === 'node') { + return { + 'X-Stainless-Lang': 'js', + 'X-Stainless-Package-Version': VERSION, + 'X-Stainless-OS': normalizePlatform((globalThis as any).process.platform), + 'X-Stainless-Arch': normalizeArch((globalThis as any).process.arch), + 'X-Stainless-Runtime': 'node', + 'X-Stainless-Runtime-Version': (globalThis as any).process.version, + }; + } + + const browserInfo = getBrowserInfo(); + if (browserInfo) { + return { + 'X-Stainless-Lang': 'js', + 'X-Stainless-Package-Version': VERSION, + 'X-Stainless-OS': 'Unknown', + 'X-Stainless-Arch': 'unknown', + 'X-Stainless-Runtime': `browser:${browserInfo.browser}`, + 'X-Stainless-Runtime-Version': browserInfo.version, + }; + } + + // TODO add support for Cloudflare workers, etc. + return { + 'X-Stainless-Lang': 'js', + 'X-Stainless-Package-Version': VERSION, + 'X-Stainless-OS': 'Unknown', + 'X-Stainless-Arch': 'unknown', + 'X-Stainless-Runtime': 'unknown', + 'X-Stainless-Runtime-Version': 'unknown', + }; +}; + +type BrowserInfo = { + browser: Browser; + version: string; +}; + +declare const navigator: { userAgent: string } | undefined; + +// Note: modified from https://github.com/JS-DevTools/host-environment/blob/b1ab79ecde37db5d6e163c050e54fe7d287d7c92/src/isomorphic.browser.ts +function getBrowserInfo(): BrowserInfo | null { + if (typeof navigator === 'undefined' || !navigator) { + return null; + } + + // NOTE: The order matters here! + const browserPatterns = [ + { key: 'edge' as const, pattern: /Edge(?:\W+(\d+)\.(\d+)(?:\.(\d+))?)?/ }, + { key: 'ie' as const, pattern: /MSIE(?:\W+(\d+)\.(\d+)(?:\.(\d+))?)?/ }, + { key: 'ie' as const, pattern: /Trident(?:.*rv\:(\d+)\.(\d+)(?:\.(\d+))?)?/ }, + { key: 'chrome' as const, pattern: /Chrome(?:\W+(\d+)\.(\d+)(?:\.(\d+))?)?/ }, + { key: 'firefox' as const, pattern: /Firefox(?:\W+(\d+)\.(\d+)(?:\.(\d+))?)?/ }, + { key: 'safari' as const, pattern: /(?:Version\W+(\d+)\.(\d+)(?:\.(\d+))?)?(?:\W+Mobile\S*)?\W+Safari/ }, + ]; + + // Find the FIRST matching browser + for (const { key, pattern } of browserPatterns) { + const match = pattern.exec(navigator.userAgent); + if (match) { + const major = match[1] || 0; + const minor = match[2] || 0; + const patch = match[3] || 0; + + return { browser: key, version: `${major}.${minor}.${patch}` }; + } + } + + return null; +} + +const normalizeArch = (arch: string): Arch => { + // Node docs: + // - https://nodejs.org/api/process.html#processarch + // Deno docs: + // - https://doc.deno.land/deno/stable/~/Deno.build + if (arch === 'x32') return 'x32'; + if (arch === 'x86_64' || arch === 'x64') return 'x64'; + if (arch === 'arm') return 'arm'; + if (arch === 'aarch64' || arch === 'arm64') return 'arm64'; + if (arch) return `other:${arch}`; + return 'unknown'; +}; + +const normalizePlatform = (platform: string): PlatformName => { + // Node platforms: + // - https://nodejs.org/api/process.html#processplatform + // Deno platforms: + // - https://doc.deno.land/deno/stable/~/Deno.build + // - https://github.com/denoland/deno/issues/14799 + + platform = platform.toLowerCase(); + + // NOTE: this iOS check is untested and may not work + // Node does not work natively on IOS, there is a fork at + // https://github.com/nodejs-mobile/nodejs-mobile + // however it is unknown at the time of writing how to detect if it is running + if (platform.includes('ios')) return 'iOS'; + if (platform === 'android') return 'Android'; + if (platform === 'darwin') return 'MacOS'; + if (platform === 'win32') return 'Windows'; + if (platform === 'freebsd') return 'FreeBSD'; + if (platform === 'openbsd') return 'OpenBSD'; + if (platform === 'linux') return 'Linux'; + if (platform) return `Other:${platform}`; + return 'Unknown'; +}; + +let _platformHeaders: PlatformProperties; +export const getPlatformHeaders = () => { + return (_platformHeaders ??= getPlatformProperties()); +}; diff --git a/src/internal/errors.ts b/src/internal/errors.ts new file mode 100644 index 0000000..82c7b14 --- /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 0000000..5cc03ce --- /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 0000000..92dec89 --- /dev/null +++ b/src/internal/parse.ts @@ -0,0 +1,50 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import type { FinalRequestOptions } from './request-options'; +import { type ScanDocuments } from '../client'; +import { formatRequestDetails, loggerFor } from './utils/log'; + +export type APIResponseProps = { + response: Response; + options: FinalRequestOptions; + controller: AbortController; + requestLogID: string; + retryOfRequestLogID: string | undefined; + startTime: number; +}; + +export async function defaultParseResponse(client: ScanDocuments, props: APIResponseProps): Promise { + const { response, requestLogID, retryOfRequestLogID, startTime } = props; + const body = await (async () => { + // 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 json as T; + } + + 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; +} diff --git a/src/internal/request-options.ts b/src/internal/request-options.ts new file mode 100644 index 0000000..d2ade9e --- /dev/null +++ b/src/internal/request-options.ts @@ -0,0 +1,37 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { NullableHeaders } from './headers'; + +import type { BodyInit } from './builtin-types'; +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; + + __binaryResponse?: boolean | undefined; +}; + +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 0000000..fe48144 --- /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 0000000..05ee204 --- /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 ScanDocuments({ 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 0000000..245e849 --- /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 0000000..d7928cd --- /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 0000000..bbf7eab --- /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 { ScanDocuments } 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: ScanDocuments | 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: ScanDocuments | 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: ScanDocuments | 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: ScanDocuments | 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 0000000..3cbfacc --- /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 0000000..7a1867b --- /dev/null +++ b/src/internal/utils/base64.ts @@ -0,0 +1,40 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { ScanDocumentsError } 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 ScanDocumentsError('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 ScanDocumentsError('Cannot decode base64 string; Expected `Buffer` or `atob` to be defined'); +}; diff --git a/src/internal/utils/bytes.ts b/src/internal/utils/bytes.ts new file mode 100644 index 0000000..8da627a --- /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 0000000..2d84800 --- /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 0000000..2bae499 --- /dev/null +++ b/src/internal/utils/log.ts @@ -0,0 +1,127 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { hasOwn } from './values'; +import { type ScanDocuments } 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: ScanDocuments, +): 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: ScanDocuments): 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() === 'x-api-key' || + 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 0000000..b56185a --- /dev/null +++ b/src/internal/utils/path.ts @@ -0,0 +1,65 @@ +import { ScanDocumentsError } 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 ScanDocumentsError( + `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 0000000..65e5296 --- /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 0000000..b0e53aa --- /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 0000000..7c833c6 --- /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 { ScanDocumentsError } 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 ScanDocumentsError(`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 ScanDocumentsError(`${name} must be an integer`); + } + if (n < 0) { + throw new ScanDocumentsError(`${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 ScanDocumentsError(`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 ScanDocumentsError(`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/.keep b/src/lib/.keep new file mode 100644 index 0000000..7554f8b --- /dev/null +++ b/src/lib/.keep @@ -0,0 +1,4 @@ +File generated from our OpenAPI spec by Stainless. + +This directory can be used to store custom files to expand the SDK. +It is ignored by Stainless code generation and its content (other than this keep file) won't be touched. diff --git a/src/resource.ts b/src/resource.ts new file mode 100644 index 0000000..363e351 --- /dev/null +++ b/src/resource.ts @@ -0,0 +1,2 @@ +/** @deprecated Import from ./core/resource instead */ +export * from './core/resource'; diff --git a/src/resources.ts b/src/resources.ts new file mode 100644 index 0000000..b283d57 --- /dev/null +++ b/src/resources.ts @@ -0,0 +1 @@ +export * from './resources/index'; diff --git a/src/resources/events.ts b/src/resources/events.ts new file mode 100644 index 0000000..d48490f --- /dev/null +++ b/src/resources/events.ts @@ -0,0 +1,618 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../core/resource'; +import * as ImageOperationsAPI from './image-operations'; +import * as PdfOperationsAPI from './pdf-operations'; +import { APIPromise } from '../core/api-promise'; +import { RequestOptions } from '../internal/request-options'; + +export class Events extends APIResource { + /** + * Retrieves a paginated list of events belonging to the authenticated user. + */ + list( + query: EventListParams | null | undefined = {}, + options?: RequestOptions, + ): APIPromise { + return this._client.get('/v1/events', { query, ...options }); + } +} + +export interface EventListResponse { + /** + * The list of events + */ + data: Array< + | EventListResponse.FileCreatedEvent + | EventListResponse.FileDeletedEvent + | EventListResponse.TaskCreatedEvent + | EventListResponse.TaskCompletedEvent + | EventListResponse.TaskDeletedEvent + | EventListResponse.TaskFailedEvent + >; + + links: EventListResponse.Links; +} + +export namespace EventListResponse { + /** + * Event emitted when a file is created + */ + export interface FileCreatedEvent { + /** + * The id of the event + */ + id: string; + + /** + * The data of the event + */ + data: FileCreatedEvent.ImageData | FileCreatedEvent.DocumentData; + + /** + * The timestamp of the moment when the event was created in ISO 8601 format + */ + timestamp: string; + + /** + * The type of the event + */ + type: 'file.created'; + } + + export namespace FileCreatedEvent { + export interface ImageData { + /** + * The ID of the file + */ + id: string; + + /** + * The name of the file + */ + name: string; + + properties: ImageData.Properties; + + /** + * The id of the task that generated this file, if any + */ + task_id: string | null; + + /** + * The MIME type of the file + */ + type: 'image/png' | 'image/jpeg' | 'image/webp'; + } + + export namespace ImageData { + export interface Properties { + /** + * The height of the image in pixels + */ + height: number; + + /** + * The size of the image in bytes + */ + size: number; + + /** + * The width of the image in pixels + */ + width: number; + } + } + + export interface DocumentData { + /** + * The ID of the file + */ + id: string; + + /** + * The name of the file + */ + name: string; + + properties: DocumentData.Properties; + + /** + * The id of the task that generated this file, if any + */ + task_id: string | null; + + /** + * The MIME type of the file + */ + type: 'application/pdf'; + } + + export namespace DocumentData { + export interface Properties { + /** + * The number of pages in the document + */ + page_count: number; + + /** + * The size of the document in bytes + */ + size: number; + } + } + } + + /** + * Event emitted when a file is deleted + */ + export interface FileDeletedEvent { + /** + * The id of the event + */ + id: string; + + /** + * The data of the event + */ + data: FileDeletedEvent.Data; + + /** + * The timestamp of the moment when the event was created in ISO 8601 format + */ + timestamp: string; + + /** + * The type of the event + */ + type: 'file.deleted'; + } + + export namespace FileDeletedEvent { + /** + * The data of the event + */ + export interface Data { + /** + * The ID of the file + */ + id: string; + + /** + * The name of the file + */ + name: string; + + /** + * The type of the file that was deleted + */ + type: 'image/png' | 'image/jpeg' | 'image/webp' | 'application/pdf'; + } + } + + /** + * Event emitted when a task is created + */ + export interface TaskCreatedEvent { + /** + * The id of the event + */ + id: string; + + /** + * The data of the event + */ + data: TaskCreatedEvent.Data; + + /** + * The timestamp of the moment when the event was created in ISO 8601 format + */ + timestamp: string; + + /** + * The type of the event + */ + type: 'task.created'; + } + + export namespace TaskCreatedEvent { + /** + * The data of the event + */ + export interface Data { + /** + * The ID of the task + */ + id: string; + + /** + * The operation of the task + */ + operation: + | 'warp' + | 'extract-text' + | 'convert' + | 'render' + | 'split' + | 'merge' + | 'extract-pages' + | 'detect-documents' + | 'apply-effect'; + } + } + + /** + * Event emitted when a task is completed + */ + export interface TaskCompletedEvent { + /** + * The id of the event + */ + id: string; + + /** + * The data of the event + */ + data: + | TaskCompletedEvent.ApplyEffectCompletedData + | TaskCompletedEvent.DetectDocumentCompletedData + | TaskCompletedEvent.WarpCompletedData + | TaskCompletedEvent.ExtractTextCompletedData + | TaskCompletedEvent.ConvertCompletedData + | TaskCompletedEvent.RenderCompletedData + | TaskCompletedEvent.SplitCompletedData + | TaskCompletedEvent.MergeCompletedData + | TaskCompletedEvent.ExtractPagesCompletedData; + + /** + * The timestamp of the moment when the event was created in ISO 8601 format + */ + timestamp: string; + + /** + * The type of the event + */ + type: 'task.completed'; + } + + export namespace TaskCompletedEvent { + /** + * Task Event Data + */ + export interface ApplyEffectCompletedData { + /** + * The ID of the task + */ + id: string; + + operation: 'apply-effect'; + + result: ApplyEffectCompletedData.Result; + } + + export namespace ApplyEffectCompletedData { + export interface Result { + generated_files: Array; + } + } + + /** + * Task Event Data + */ + export interface DetectDocumentCompletedData { + /** + * The ID of the task + */ + id: string; + + operation: 'detect-documents'; + + result: DetectDocumentCompletedData.Result; + } + + export namespace DetectDocumentCompletedData { + export interface Result { + /** + * The list of documents detected in the image + */ + documents: Array; + } + + export namespace Result { + export interface Document { + /** + * The rectangle that contains the document in the image + */ + bounding_box: ImageOperationsAPI.BoundingBox; + + /** + * The coordinates of the vertex inside the image + */ + vertices: Array; + } + } + } + + /** + * Task Event Data + */ + export interface WarpCompletedData { + /** + * The ID of the task + */ + id: string; + + operation: 'warp'; + + result: WarpCompletedData.Result; + } + + export namespace WarpCompletedData { + export interface Result { + generated_files: Array; + } + } + + /** + * Task Event Data + */ + export interface ExtractTextCompletedData { + /** + * The ID of the task + */ + id: string; + + operation: 'extract-text'; + + result: ExtractTextCompletedData.Result; + } + + export namespace ExtractTextCompletedData { + export interface Result { + content: string; + + format: 'plain' | 'markdown' | 'html' | 'json'; + } + } + + /** + * Task Event Data + */ + export interface ConvertCompletedData { + /** + * The ID of the task + */ + id: string; + + operation: 'convert'; + + result: ConvertCompletedData.Result; + } + + export namespace ConvertCompletedData { + export interface Result { + generated_files: Array; + } + } + + /** + * Task Event Data + */ + export interface RenderCompletedData { + /** + * The ID of the task + */ + id: string; + + operation: 'render'; + + result: RenderCompletedData.Result; + } + + export namespace RenderCompletedData { + export interface Result { + generated_files: Array; + } + } + + /** + * Task Event Data + */ + export interface SplitCompletedData { + /** + * The ID of the task + */ + id: string; + + operation: 'split'; + + result: SplitCompletedData.Result; + } + + export namespace SplitCompletedData { + export interface Result { + generated_files: Array; + } + } + + /** + * Task Event Data + */ + export interface MergeCompletedData { + /** + * The ID of the task + */ + id: string; + + operation: 'merge'; + + result: MergeCompletedData.Result; + } + + export namespace MergeCompletedData { + export interface Result { + generated_files: Array; + } + } + + /** + * Task Event Data + */ + export interface ExtractPagesCompletedData { + /** + * The ID of the task + */ + id: string; + + operation: 'extract-pages'; + + result: ExtractPagesCompletedData.Result; + } + + export namespace ExtractPagesCompletedData { + export interface Result { + generated_files: Array; + } + } + } + + /** + * Event emitted when a task is deleted + */ + export interface TaskDeletedEvent { + /** + * The id of the event + */ + id: string; + + /** + * The data of the event + */ + data: TaskDeletedEvent.Data; + + /** + * The timestamp of the moment when the event was created in ISO 8601 format + */ + timestamp: string; + + /** + * The type of the event + */ + type: 'task.deleted'; + } + + export namespace TaskDeletedEvent { + /** + * The data of the event + */ + export interface Data { + /** + * The ID of the task + */ + id: string; + + /** + * The operation of the task + */ + operation: + | 'warp' + | 'extract-text' + | 'convert' + | 'render' + | 'split' + | 'merge' + | 'extract-pages' + | 'detect-documents' + | 'apply-effect'; + } + } + + /** + * Event emitted when a task fails + */ + export interface TaskFailedEvent { + /** + * The id of the event + */ + id: string; + + /** + * The data of the event + */ + data: TaskFailedEvent.Data; + + /** + * The timestamp of the moment when the event was created in ISO 8601 format + */ + timestamp: string; + + /** + * The type of the event + */ + type: 'task.failed'; + } + + export namespace TaskFailedEvent { + /** + * The data of the event + */ + export interface Data { + /** + * The ID of the task + */ + id: string; + + /** + * The operation of the task + */ + operation: + | 'warp' + | 'extract-text' + | 'convert' + | 'render' + | 'split' + | 'merge' + | 'extract-pages' + | 'detect-documents' + | 'apply-effect'; + + result: Data.Result; + } + + export namespace Data { + export interface Result { + /** + * Additional details about the error + */ + details: Record; + + /** + * The error message + */ + error: string; + } + } + } + + export interface Links { + /** + * The URL to the next page of results + */ + next: string | null; + + /** + * The URL to the previous page of results + */ + previous: string | null; + } +} + +export interface EventListParams { + from?: string; + + take?: number; +} + +export declare namespace Events { + export { type EventListResponse as EventListResponse, type EventListParams as EventListParams }; +} diff --git a/src/resources/files.ts b/src/resources/files.ts new file mode 100644 index 0000000..f955ef4 --- /dev/null +++ b/src/resources/files.ts @@ -0,0 +1,247 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../core/resource'; +import { APIPromise } from '../core/api-promise'; +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 { + /** + * Retrieves the data for a specific file by its ID. + * + * @example + * ```ts + * const file = await client.files.retrieve('id'); + * ``` + */ + retrieve(id: string, options?: RequestOptions): APIPromise { + return this._client.get(path`/v1/files/${id}`, options); + } + + /** + * Retrieves a paginated list of files belonging to the authenticated user. + * + * @example + * ```ts + * const files = await client.files.list(); + * ``` + */ + list( + query: FileListParams | null | undefined = {}, + options?: RequestOptions, + ): APIPromise { + return this._client.get('/v1/files', { query, ...options }); + } + + /** + * Deletes a specific file by its ID. + * + * @example + * ```ts + * await client.files.delete('id'); + * ``` + */ + delete(id: string, options?: RequestOptions): APIPromise { + return this._client.delete(path`/v1/files/${id}`, { + ...options, + headers: buildHeaders([{ Accept: '*/*' }, options?.headers]), + }); + } + + /** + * Downloads the content of a specific file by its ID. + * + * @example + * ```ts + * const response = await client.files.download('id'); + * + * const content = await response.blob(); + * console.log(content); + * ``` + */ + download(id: string, options?: RequestOptions): APIPromise { + return this._client.get(path`/v1/files/${id}/download`, { + ...options, + headers: buildHeaders([{ Accept: 'image/*' }, options?.headers]), + __binaryResponse: true, + }); + } + + /** + * Uploads a file to the user's storage. The file size is limited to 10MB. + * + * @example + * ```ts + * const file = await client.files.upload({ + * file: fs.createReadStream('path/to/file'), + * name: 'File Name', + * }); + * ``` + */ + upload(body: FileUploadParams, options?: RequestOptions): APIPromise { + return this._client.post('/v1/files', multipartFormRequestOptions({ body, ...options }, this._client)); + } +} + +/** + * The response for a file. Properties depend on the file type. + */ +export type File = File.ImageResponse | File.DocumentResponse; + +export namespace File { + /** + * The response for an image file + */ + export interface ImageResponse { + /** + * The id of the file + */ + id: string; + + /** + * The creation date of the file in ISO format + */ + created_at: string; + + /** + * The name of the file + */ + name: string; + + properties: ImageResponse.Properties; + + /** + * The id of the task that generated this file, if any + */ + task_id: string | null; + + /** + * The MIME type of the file + */ + type: 'image/png' | 'image/jpeg' | 'image/webp'; + } + + export namespace ImageResponse { + export interface Properties { + /** + * The height of the image in pixels + */ + height: number; + + /** + * The size of the image in bytes + */ + size: number; + + /** + * The width of the image in pixels + */ + width: number; + } + } + + /** + * The response for a document file + */ + export interface DocumentResponse { + /** + * The id of the file + */ + id: string; + + /** + * The creation date of the file in ISO format + */ + created_at: string; + + /** + * The name of the file + */ + name: string; + + properties: DocumentResponse.Properties; + + /** + * The id of the task that generated this file, if any + */ + task_id: string | null; + + /** + * The MIME type of the file + */ + type: 'application/pdf'; + } + + export namespace DocumentResponse { + export interface Properties { + /** + * The number of pages in the document + */ + page_count: number; + + /** + * The size of the document in bytes + */ + size: number; + } + } +} + +export interface FileListResponse { + /** + * The list of files + */ + data: Array; + + links: FileListResponse.Links; +} + +export namespace FileListResponse { + export interface Links { + /** + * The URL to the next page of results + */ + next: string | null; + + /** + * The URL to the previous page of results + */ + previous: string | null; + } +} + +export interface FileListParams { + /** + * The id of the file from which to start the search + */ + from?: string; + + /** + * The number of elements to retrieve + */ + take?: number; +} + +export interface FileUploadParams { + /** + * The file to upload + */ + file: Uploadable; + + /** + * The name of the file + */ + name: string; +} + +export declare namespace Files { + export { + type File as File, + type FileListResponse as FileListResponse, + type FileListParams as FileListParams, + type FileUploadParams as FileUploadParams, + }; +} diff --git a/src/resources/image-operations.ts b/src/resources/image-operations.ts new file mode 100644 index 0000000..b9a1acc --- /dev/null +++ b/src/resources/image-operations.ts @@ -0,0 +1,1520 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../core/resource'; +import * as ImageOperationsAPI from './image-operations'; +import { APIPromise } from '../core/api-promise'; +import { RequestOptions } from '../internal/request-options'; + +export class ImageOperations extends APIResource { + /** + * Creates a task to apply a specified visual effect to an image. + * + * @example + * ```ts + * const applyEffectResponse = + * await client.imageOperations.applyEffect({ + * effect: 'grayscale', + * input: 'file_avyrvozb9302uwhq', + * }); + * ``` + */ + applyEffect( + body: ImageOperationApplyEffectParams, + options?: RequestOptions, + ): APIPromise { + return this._client.post('/v1/image-operations/apply-effect', { body, ...options }); + } + + /** + * Creates a task to convert an image file to a different format. + * + * @example + * ```ts + * const convertResponse = + * await client.imageOperations.convert({ + * input: 'file_avyrvozb9302uwhq', + * target_format: 'image/png', + * }); + * ``` + */ + convert(body: ImageOperationConvertParams, options?: RequestOptions): APIPromise { + return this._client.post('/v1/image-operations/convert', { body, ...options }); + } + + /** + * Creates a task to detect document boundaries within an image. + * + * @example + * ```ts + * const detectDocumentsResponse = + * await client.imageOperations.detectDocuments({ + * input: 'file_avyrvozb9302uwhq', + * }); + * ``` + */ + detectDocuments( + body: ImageOperationDetectDocumentsParams, + options?: RequestOptions, + ): APIPromise { + return this._client.post('/v1/image-operations/detect-documents', { body, ...options }); + } + + /** + * Creates a task to extract text from a specified image file. + * + * @example + * ```ts + * const extractTextResponse = + * await client.imageOperations.extractText({ + * format: 'plain', + * input: 'file_avyrvozb9302uwhq', + * }); + * ``` + */ + extractText( + body: ImageOperationExtractTextParams, + options?: RequestOptions, + ): APIPromise { + return this._client.post('/v1/image-operations/extract-text', { body, ...options }); + } + + /** + * Creates a task to apply perspective correction (warp) to an image based on + * detected document boundaries. + * + * @example + * ```ts + * const warpResponse = await client.imageOperations.warp({ + * input: 'file_avyrvozb9302uwhq', + * vertices: [ + * { x: 0, y: 0 }, + * { x: 100, y: 10 }, + * { x: 100, y: 100 }, + * { x: 0, y: 90 }, + * ], + * }); + * ``` + */ + warp(body: ImageOperationWarpParams, options?: RequestOptions): APIPromise { + return this._client.post('/v1/image-operations/warp', { body, ...options }); + } +} + +/** + * The response of an apply-effect task + */ +export type ApplyEffectResponse = + | ApplyEffectResponse.CompletedApplyEffectTaskResponse + | ApplyEffectResponse.PendingApplyEffectTaskResponse + | ApplyEffectResponse.ProcessingApplyEffectTaskResponse + | ApplyEffectResponse.FailedApplyEffectTaskResponse; + +export namespace ApplyEffectResponse { + export interface CompletedApplyEffectTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'apply-effect'; + + parameters: CompletedApplyEffectTaskResponse.Parameters; + + result: CompletedApplyEffectTaskResponse.Result; + + /** + * The current status of the task. + */ + status: 'completed'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace CompletedApplyEffectTaskResponse { + export interface Parameters { + /** + * The effect to apply to the image + */ + effect: 'grayscale' | 'scanner' | 'black-background'; + + /** + * The id of the file to operate on. + */ + input: string; + + /** + * The name of the file + */ + name?: string; + } + + export interface Result { + generated_files: Array; + } + } + + export interface PendingApplyEffectTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'apply-effect'; + + parameters: PendingApplyEffectTaskResponse.Parameters; + + result: unknown; + + /** + * The current status of the task. + */ + status: 'pending'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace PendingApplyEffectTaskResponse { + export interface Parameters { + /** + * The effect to apply to the image + */ + effect: 'grayscale' | 'scanner' | 'black-background'; + + /** + * The id of the file to operate on. + */ + input: string; + + /** + * The name of the file + */ + name?: string; + } + } + + export interface ProcessingApplyEffectTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'apply-effect'; + + parameters: ProcessingApplyEffectTaskResponse.Parameters; + + result: unknown; + + /** + * The current status of the task. + */ + status: 'processing'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace ProcessingApplyEffectTaskResponse { + export interface Parameters { + /** + * The effect to apply to the image + */ + effect: 'grayscale' | 'scanner' | 'black-background'; + + /** + * The id of the file to operate on. + */ + input: string; + + /** + * The name of the file + */ + name?: string; + } + } + + export interface FailedApplyEffectTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'apply-effect'; + + parameters: FailedApplyEffectTaskResponse.Parameters; + + result: FailedApplyEffectTaskResponse.Result; + + /** + * The current status of the task. + */ + status: 'failed'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace FailedApplyEffectTaskResponse { + export interface Parameters { + /** + * The effect to apply to the image + */ + effect: 'grayscale' | 'scanner' | 'black-background'; + + /** + * The id of the file to operate on. + */ + input: string; + + /** + * The name of the file + */ + name?: string; + } + + export interface Result { + details: Record; + + error: string; + } + } +} + +/** + * The rectangle that contains the document in the image + */ +export interface BoundingBox { + /** + * The height of the bounding box inside the image in pixels + */ + height: number; + + /** + * The position of the top-left corner of the bounding box inside the image in + * pixels + */ + left: number; + + /** + * The position of the top-left corner of the bounding box inside the image in + * pixels + */ + top: number; + + /** + * The width of the bounding box inside the image in pixels + */ + width: number; +} + +export type ConvertRequest = + | ConvertRequest.PngOptions + | ConvertRequest.JpegOptions + | ConvertRequest.WebpOptions; + +export namespace ConvertRequest { + export interface PngOptions { + /** + * The id of the file to operate on. + */ + input: string; + + /** + * The format to convert the image to. + */ + target_format: 'image/png'; + + /** + * The name of the file + */ + name?: string; + } + + export interface JpegOptions { + /** + * The id of the file to operate on. + */ + input: string; + + /** + * Image quality (1-100) for lossy formats like jpeg. + */ + quality: number; + + /** + * The format to convert the image to. + */ + target_format: 'image/jpeg'; + + /** + * The name of the file + */ + name?: string; + } + + export interface WebpOptions { + /** + * The id of the file to operate on. + */ + input: string; + + /** + * Image quality (1-100) for lossy formats like webp. + */ + quality: number; + + /** + * The format to convert the image to. + */ + target_format: 'image/webp'; + + /** + * The name of the file + */ + name?: string; + } +} + +/** + * The response of an convert task + */ +export type ConvertResponse = + | ConvertResponse.CompletedConvertTaskResponse + | ConvertResponse.PendingConvertTaskResponse + | ConvertResponse.ProcessingConvertTaskResponse + | ConvertResponse.FailedConvertTaskResponse; + +export namespace ConvertResponse { + export interface CompletedConvertTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'convert'; + + parameters: ImageOperationsAPI.ConvertRequest; + + result: CompletedConvertTaskResponse.Result; + + /** + * The current status of the task. + */ + status: 'completed'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace CompletedConvertTaskResponse { + export interface Result { + generated_files: Array; + } + } + + export interface PendingConvertTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'convert'; + + parameters: ImageOperationsAPI.ConvertRequest; + + result: unknown; + + /** + * The current status of the task. + */ + status: 'pending'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export interface ProcessingConvertTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'convert'; + + parameters: ImageOperationsAPI.ConvertRequest; + + result: unknown; + + /** + * The current status of the task. + */ + status: 'processing'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export interface FailedConvertTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'convert'; + + parameters: ImageOperationsAPI.ConvertRequest; + + result: FailedConvertTaskResponse.Result; + + /** + * The current status of the task. + */ + status: 'failed'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace FailedConvertTaskResponse { + export interface Result { + details: Record; + + error: string; + } + } +} + +export interface CoordinatesItem { + /** + * The x coordinate of the vertex inside the image in pixels + */ + x: number; + + /** + * The y coordinate of the vertex inside the image in pixels + */ + y: number; +} + +/** + * The response of the detect-documents operation + */ +export type DetectDocumentsResponse = + | DetectDocumentsResponse.CompletedConvertTaskResponse + | DetectDocumentsResponse.PendingConvertTaskResponse + | DetectDocumentsResponse.ProcessingConvertTaskResponse + | DetectDocumentsResponse.FailedConvertTaskResponse; + +export namespace DetectDocumentsResponse { + export interface CompletedConvertTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'convert'; + + parameters: ImageOperationsAPI.ConvertRequest; + + result: CompletedConvertTaskResponse.Result; + + /** + * The current status of the task. + */ + status: 'completed'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace CompletedConvertTaskResponse { + export interface Result { + /** + * The list of documents detected in the image + */ + documents: Array; + } + + export namespace Result { + export interface Document { + /** + * The rectangle that contains the document in the image + */ + bounding_box: ImageOperationsAPI.BoundingBox; + + /** + * The coordinates of the vertex inside the image + */ + vertices: Array; + } + } + } + + export interface PendingConvertTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'convert'; + + parameters: ImageOperationsAPI.ConvertRequest; + + result: unknown; + + /** + * The current status of the task. + */ + status: 'pending'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export interface ProcessingConvertTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'convert'; + + parameters: ImageOperationsAPI.ConvertRequest; + + result: unknown; + + /** + * The current status of the task. + */ + status: 'processing'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export interface FailedConvertTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'convert'; + + parameters: ImageOperationsAPI.ConvertRequest; + + result: FailedConvertTaskResponse.Result; + + /** + * The current status of the task. + */ + status: 'failed'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace FailedConvertTaskResponse { + export interface Result { + details: Record; + + error: string; + } + } +} + +/** + * Extract text from an image in various formats. + */ +export type ExtractTextRequest = + | ExtractTextRequest.Plain + | ExtractTextRequest.Markdown + | ExtractTextRequest.HTML + | ExtractTextRequest.Json; + +export namespace ExtractTextRequest { + export interface Plain { + /** + * The format of the text to be extracted. + */ + format: 'plain'; + + /** + * The id of the file to operate on. + */ + input: string; + } + + export interface Markdown { + /** + * The format of the text to be extracted. + */ + format: 'markdown'; + + /** + * The id of the file to operate on. + */ + input: string; + } + + export interface HTML { + /** + * The format of the text to be extracted. + */ + format: 'html'; + + /** + * The id of the file to operate on. + */ + input: string; + } + + export interface Json { + /** + * The format of the text to be extracted. + */ + format: 'json'; + + /** + * The id of the file to operate on. + */ + input: string; + + /** + * An OpenAPI schema object describing the expected JSON structure. Required if + * format is 'json'. + */ + schema: Json.Schema; + } + + export namespace Json { + /** + * An OpenAPI schema object describing the expected JSON structure. Required if + * format is 'json'. + */ + export interface Schema { + description?: string; + + example?: unknown; + + format?: string; + + items?: Schema.Items; + + properties?: Record; + + required?: Array; + + type?: 'string' | 'number' | 'integer' | 'boolean' | 'array' | 'object'; + + [k: string]: unknown; + } + + export namespace Schema { + export interface Items { + description?: string; + + example?: unknown; + + format?: string; + + items?: unknown; + + properties?: Record; + + required?: Array; + + type?: 'string' | 'number' | 'integer' | 'boolean' | 'array' | 'object'; + + [k: string]: unknown; + } + + export interface Properties { + description?: string; + + example?: unknown; + + format?: string; + + items?: unknown; + + properties?: Record; + + required?: Array; + + type?: 'string' | 'number' | 'integer' | 'boolean' | 'array' | 'object'; + + [k: string]: unknown; + } + } + } +} + +/** + * The response of an extract-text task + */ +export type ExtractTextResponse = + | ExtractTextResponse.CompletedExtractTextTaskResponse + | ExtractTextResponse.PendingExtractTextTaskResponse + | ExtractTextResponse.ProcessingExtractTextTaskResponse + | ExtractTextResponse.FailedExtractTextTaskResponse; + +export namespace ExtractTextResponse { + export interface CompletedExtractTextTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'extract-text'; + + /** + * Extract text from an image in various formats. + */ + parameters: ImageOperationsAPI.ExtractTextRequest; + + result: CompletedExtractTextTaskResponse.Result; + + /** + * The current status of the task. + */ + status: 'completed'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace CompletedExtractTextTaskResponse { + export interface Result { + content: string; + + format: 'plain' | 'markdown' | 'html' | 'json'; + } + } + + export interface PendingExtractTextTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'extract-text'; + + /** + * Extract text from an image in various formats. + */ + parameters: ImageOperationsAPI.ExtractTextRequest; + + result: unknown; + + /** + * The current status of the task. + */ + status: 'pending'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export interface ProcessingExtractTextTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'extract-text'; + + /** + * Extract text from an image in various formats. + */ + parameters: ImageOperationsAPI.ExtractTextRequest; + + result: unknown; + + /** + * The current status of the task. + */ + status: 'processing'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export interface FailedExtractTextTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'extract-text'; + + /** + * Extract text from an image in various formats. + */ + parameters: ImageOperationsAPI.ExtractTextRequest; + + result: FailedExtractTextTaskResponse.Result; + + /** + * The current status of the task. + */ + status: 'failed'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace FailedExtractTextTaskResponse { + export interface Result { + details: Record; + + error: string; + } + } +} + +/** + * The response for an image file from a task + */ +export interface ImageFromTaskResponse { + /** + * The id of the file + */ + id: string; + + /** + * The creation date of the file in ISO format + */ + created_at: string; + + /** + * The name of the file + */ + name: string; + + properties: ImageFromTaskResponse.Properties; + + /** + * The id of the task that generated this file + */ + task_id: string; + + /** + * The MIME type of the file + */ + type: 'image/png' | 'image/jpeg' | 'image/webp'; +} + +export namespace ImageFromTaskResponse { + export interface Properties { + /** + * The height of the image in pixels + */ + height: number; + + /** + * The size of the image in bytes + */ + size: number; + + /** + * The width of the image in pixels + */ + width: number; + } +} + +/** + * Transform an image by warping it to a quadrilateral. + */ +export interface WarpRequest { + /** + * The id of the file to operate on. + */ + input: string; + + /** + * Coordinates of the 4 vertices of the quadrilateral to warp the image to. + */ + vertices: Array; + + /** + * The name of the file + */ + name?: string; +} + +/** + * The response of an warp task + */ +export type WarpResponse = + | WarpResponse.CompletedWarpTaskResponse + | WarpResponse.PendingWarpTaskResponse + | WarpResponse.ProcessingWarpTaskResponse + | WarpResponse.FailedWarpTaskResponse; + +export namespace WarpResponse { + export interface CompletedWarpTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'warp'; + + /** + * Transform an image by warping it to a quadrilateral. + */ + parameters: ImageOperationsAPI.WarpRequest; + + result: CompletedWarpTaskResponse.Result; + + /** + * The current status of the task. + */ + status: 'completed'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace CompletedWarpTaskResponse { + export interface Result { + generated_files: Array; + } + } + + export interface PendingWarpTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'warp'; + + /** + * Transform an image by warping it to a quadrilateral. + */ + parameters: ImageOperationsAPI.WarpRequest; + + result: unknown; + + /** + * The current status of the task. + */ + status: 'pending'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export interface ProcessingWarpTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'warp'; + + /** + * Transform an image by warping it to a quadrilateral. + */ + parameters: ImageOperationsAPI.WarpRequest; + + result: unknown; + + /** + * The current status of the task. + */ + status: 'processing'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export interface FailedWarpTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'warp'; + + /** + * Transform an image by warping it to a quadrilateral. + */ + parameters: ImageOperationsAPI.WarpRequest; + + result: FailedWarpTaskResponse.Result; + + /** + * The current status of the task. + */ + status: 'failed'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace FailedWarpTaskResponse { + export interface Result { + details: Record; + + error: string; + } + } +} + +export interface ImageOperationApplyEffectParams { + /** + * The effect to apply to the image + */ + effect: 'grayscale' | 'scanner' | 'black-background'; + + /** + * The id of the file to operate on. + */ + input: string; + + /** + * The name of the file + */ + name?: string; +} + +export type ImageOperationConvertParams = + | ImageOperationConvertParams.PngOptions + | ImageOperationConvertParams.JpegOptions + | ImageOperationConvertParams.WebpOptions; + +export declare namespace ImageOperationConvertParams { + export interface PngOptions { + /** + * The id of the file to operate on. + */ + input: string; + + /** + * The format to convert the image to. + */ + target_format: 'image/png'; + + /** + * The name of the file + */ + name?: string; + } + + export interface JpegOptions { + /** + * The id of the file to operate on. + */ + input: string; + + /** + * Image quality (1-100) for lossy formats like jpeg. + */ + quality: number; + + /** + * The format to convert the image to. + */ + target_format: 'image/jpeg'; + + /** + * The name of the file + */ + name?: string; + } + + export interface WebpOptions { + /** + * The id of the file to operate on. + */ + input: string; + + /** + * Image quality (1-100) for lossy formats like webp. + */ + quality: number; + + /** + * The format to convert the image to. + */ + target_format: 'image/webp'; + + /** + * The name of the file + */ + name?: string; + } +} + +export interface ImageOperationDetectDocumentsParams { + /** + * The id of the file to operate on. + */ + input: string; +} + +export type ImageOperationExtractTextParams = + | ImageOperationExtractTextParams.Plain + | ImageOperationExtractTextParams.Markdown + | ImageOperationExtractTextParams.HTML + | ImageOperationExtractTextParams.Json; + +export declare namespace ImageOperationExtractTextParams { + export interface Plain { + /** + * The format of the text to be extracted. + */ + format: 'plain'; + + /** + * The id of the file to operate on. + */ + input: string; + } + + export interface Markdown { + /** + * The format of the text to be extracted. + */ + format: 'markdown'; + + /** + * The id of the file to operate on. + */ + input: string; + } + + export interface HTML { + /** + * The format of the text to be extracted. + */ + format: 'html'; + + /** + * The id of the file to operate on. + */ + input: string; + } + + export interface Json { + /** + * The format of the text to be extracted. + */ + format: 'json'; + + /** + * The id of the file to operate on. + */ + input: string; + + /** + * An OpenAPI schema object describing the expected JSON structure. Required if + * format is 'json'. + */ + schema: Json.Schema; + } + + export namespace Json { + /** + * An OpenAPI schema object describing the expected JSON structure. Required if + * format is 'json'. + */ + export interface Schema { + description?: string; + + example?: unknown; + + format?: string; + + items?: Schema.Items; + + properties?: Record; + + required?: Array; + + type?: 'string' | 'number' | 'integer' | 'boolean' | 'array' | 'object'; + + [k: string]: unknown; + } + + export namespace Schema { + export interface Items { + description?: string; + + example?: unknown; + + format?: string; + + items?: unknown; + + properties?: Record; + + required?: Array; + + type?: 'string' | 'number' | 'integer' | 'boolean' | 'array' | 'object'; + + [k: string]: unknown; + } + + export interface Properties { + description?: string; + + example?: unknown; + + format?: string; + + items?: unknown; + + properties?: Record; + + required?: Array; + + type?: 'string' | 'number' | 'integer' | 'boolean' | 'array' | 'object'; + + [k: string]: unknown; + } + } + } +} + +export interface ImageOperationWarpParams { + /** + * The id of the file to operate on. + */ + input: string; + + /** + * Coordinates of the 4 vertices of the quadrilateral to warp the image to. + */ + vertices: Array; + + /** + * The name of the file + */ + name?: string; +} + +export declare namespace ImageOperations { + export { + type ApplyEffectResponse as ApplyEffectResponse, + type BoundingBox as BoundingBox, + type ConvertRequest as ConvertRequest, + type ConvertResponse as ConvertResponse, + type CoordinatesItem as CoordinatesItem, + type DetectDocumentsResponse as DetectDocumentsResponse, + type ExtractTextRequest as ExtractTextRequest, + type ExtractTextResponse as ExtractTextResponse, + type ImageFromTaskResponse as ImageFromTaskResponse, + type WarpRequest as WarpRequest, + type WarpResponse as WarpResponse, + type ImageOperationApplyEffectParams as ImageOperationApplyEffectParams, + type ImageOperationConvertParams as ImageOperationConvertParams, + type ImageOperationDetectDocumentsParams as ImageOperationDetectDocumentsParams, + type ImageOperationExtractTextParams as ImageOperationExtractTextParams, + type ImageOperationWarpParams as ImageOperationWarpParams, + }; +} diff --git a/src/resources/index.ts b/src/resources/index.ts new file mode 100644 index 0000000..fd22245 --- /dev/null +++ b/src/resources/index.ts @@ -0,0 +1,36 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export { Events, type EventListResponse, type EventListParams } from './events'; +export { Files, type File, type FileListResponse, type FileListParams, type FileUploadParams } from './files'; +export { + ImageOperations, + type ApplyEffectResponse, + type BoundingBox, + type ConvertRequest, + type ConvertResponse, + type CoordinatesItem, + type DetectDocumentsResponse, + type ExtractTextRequest, + type ExtractTextResponse, + type ImageFromTaskResponse, + type WarpRequest, + type WarpResponse, + type ImageOperationApplyEffectParams, + type ImageOperationConvertParams, + type ImageOperationDetectDocumentsParams, + type ImageOperationExtractTextParams, + type ImageOperationWarpParams, +} from './image-operations'; +export { + PdfOperations, + type DocumentFromTask, + type ExtractPages, + type Merge, + type Render, + type Split, + type PdfOperationExtractPagesParams, + type PdfOperationMergeParams, + type PdfOperationRenderParams, + type PdfOperationSplitParams, +} from './pdf-operations'; +export { Tasks, type TaskResponse, type TaskListResponse, type TaskListParams } from './tasks'; diff --git a/src/resources/pdf-operations.ts b/src/resources/pdf-operations.ts new file mode 100644 index 0000000..035c49d --- /dev/null +++ b/src/resources/pdf-operations.ts @@ -0,0 +1,1054 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../core/resource'; +import * as PdfOperationsAPI from './pdf-operations'; +import * as ImageOperationsAPI from './image-operations'; +import { APIPromise } from '../core/api-promise'; +import { RequestOptions } from '../internal/request-options'; + +export class PdfOperations extends APIResource { + /** + * Creates a task to extract specific pages from a PDF file into a new PDF file. + * + * @example + * ```ts + * const extractPages = + * await client.pdfOperations.extractPages({ + * input: 'file_avyrvozb9302uwhq', + * pages: '2-7', + * }); + * ``` + */ + extractPages(body: PdfOperationExtractPagesParams, options?: RequestOptions): APIPromise { + return this._client.post('/v1/pdf-operations/extract-pages', { body, ...options }); + } + + /** + * Creates a task to merge multiple PDF and/or image files into a single PDF file. + * + * @example + * ```ts + * const merge = await client.pdfOperations.merge({ + * input: ['file_avyrvozb9302uwhq'], + * }); + * ``` + */ + merge(body: PdfOperationMergeParams, options?: RequestOptions): APIPromise { + return this._client.post('/v1/pdf-operations/merge', { body, ...options }); + } + + /** + * Creates a task to render specified pages of a PDF file as images. + * + * @example + * ```ts + * const render = await client.pdfOperations.render({ + * input: 'file_avyrvozb9302uwhq', + * }); + * ``` + */ + render(body: PdfOperationRenderParams, options?: RequestOptions): APIPromise { + return this._client.post('/v1/pdf-operations/render', { body, ...options }); + } + + /** + * Creates a task to split a PDF file into multiple single-page PDF files. + * + * @example + * ```ts + * const split = await client.pdfOperations.split({ + * input: 'file_avyrvozb9302uwhq', + * }); + * ``` + */ + split(body: PdfOperationSplitParams, options?: RequestOptions): APIPromise { + return this._client.post('/v1/pdf-operations/split', { body, ...options }); + } +} + +/** + * The response for a document file from a task + */ +export interface DocumentFromTask { + /** + * The id of the file + */ + id: string; + + /** + * The creation date of the file in ISO format + */ + created_at: string; + + /** + * The name of the file + */ + name: string; + + properties: DocumentFromTask.Properties; + + /** + * The id of the task that generated this file + */ + task_id: string; + + /** + * The MIME type of the file + */ + type: 'application/pdf'; +} + +export namespace DocumentFromTask { + export interface Properties { + /** + * The number of pages in the document + */ + page_count: number; + + /** + * The size of the document in bytes + */ + size: number; + } +} + +/** + * The response of an extract task + */ +export type ExtractPages = + | ExtractPages.CompletedExtractPagesTaskResponse + | ExtractPages.PendingExtractPagesTaskResponse + | ExtractPages.ProcessingExtractPagesTaskResponse + | ExtractPages.FailedExtractPagesTaskResponse; + +export namespace ExtractPages { + export interface CompletedExtractPagesTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'extract-pages'; + + parameters: CompletedExtractPagesTaskResponse.Parameters; + + result: CompletedExtractPagesTaskResponse.Result; + + /** + * The current status of the task. + */ + status: 'completed'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace CompletedExtractPagesTaskResponse { + export interface Parameters { + /** + * The id of the file to operate on. + */ + input: string; + + /** + * Page range (e.g., 2-7), a comma-separated list (e.g., 2,3,7) of pages. + */ + pages: string; + + /** + * The name of the file + */ + name?: string; + } + + export interface Result { + generated_files: Array; + } + } + + export interface PendingExtractPagesTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'extract-pages'; + + parameters: PendingExtractPagesTaskResponse.Parameters; + + result: unknown; + + /** + * The current status of the task. + */ + status: 'pending'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace PendingExtractPagesTaskResponse { + export interface Parameters { + /** + * The id of the file to operate on. + */ + input: string; + + /** + * Page range (e.g., 2-7), a comma-separated list (e.g., 2,3,7) of pages. + */ + pages: string; + + /** + * The name of the file + */ + name?: string; + } + } + + export interface ProcessingExtractPagesTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'extract-pages'; + + parameters: ProcessingExtractPagesTaskResponse.Parameters; + + result: unknown; + + /** + * The current status of the task. + */ + status: 'processing'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace ProcessingExtractPagesTaskResponse { + export interface Parameters { + /** + * The id of the file to operate on. + */ + input: string; + + /** + * Page range (e.g., 2-7), a comma-separated list (e.g., 2,3,7) of pages. + */ + pages: string; + + /** + * The name of the file + */ + name?: string; + } + } + + export interface FailedExtractPagesTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'extract-pages'; + + parameters: FailedExtractPagesTaskResponse.Parameters; + + result: FailedExtractPagesTaskResponse.Result; + + /** + * The current status of the task. + */ + status: 'failed'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace FailedExtractPagesTaskResponse { + export interface Parameters { + /** + * The id of the file to operate on. + */ + input: string; + + /** + * Page range (e.g., 2-7), a comma-separated list (e.g., 2,3,7) of pages. + */ + pages: string; + + /** + * The name of the file + */ + name?: string; + } + + export interface Result { + details: Record; + + error: string; + } + } +} + +/** + * The response of an merge task + */ +export type Merge = + | Merge.CompletedMergeTaskResponse + | Merge.PendingMergeTaskResponse + | Merge.ProcessingMergeTaskResponse + | Merge.FailedMergeTaskResponse; + +export namespace Merge { + export interface CompletedMergeTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'merge'; + + parameters: CompletedMergeTaskResponse.Parameters; + + result: CompletedMergeTaskResponse.Result; + + /** + * The current status of the task. + */ + status: 'completed'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace CompletedMergeTaskResponse { + export interface Parameters { + /** + * The list of ids of the files to be merged + */ + input: Array; + + /** + * The name of the file + */ + name?: string; + } + + export interface Result { + generated_files: Array; + } + } + + export interface PendingMergeTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'merge'; + + parameters: PendingMergeTaskResponse.Parameters; + + result: unknown; + + /** + * The current status of the task. + */ + status: 'pending'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace PendingMergeTaskResponse { + export interface Parameters { + /** + * The list of ids of the files to be merged + */ + input: Array; + + /** + * The name of the file + */ + name?: string; + } + } + + export interface ProcessingMergeTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'merge'; + + parameters: ProcessingMergeTaskResponse.Parameters; + + result: unknown; + + /** + * The current status of the task. + */ + status: 'processing'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace ProcessingMergeTaskResponse { + export interface Parameters { + /** + * The list of ids of the files to be merged + */ + input: Array; + + /** + * The name of the file + */ + name?: string; + } + } + + export interface FailedMergeTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'merge'; + + parameters: FailedMergeTaskResponse.Parameters; + + result: FailedMergeTaskResponse.Result; + + /** + * The current status of the task. + */ + status: 'failed'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace FailedMergeTaskResponse { + export interface Parameters { + /** + * The list of ids of the files to be merged + */ + input: Array; + + /** + * The name of the file + */ + name?: string; + } + + export interface Result { + details: Record; + + error: string; + } + } +} + +/** + * The response of an render task + */ +export type Render = + | Render.CompletedRenderTaskResponse + | Render.PendingRenderTaskResponse + | Render.ProcessingRenderTaskResponse + | Render.FailedRenderTaskResponse; + +export namespace Render { + export interface CompletedRenderTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'render'; + + parameters: CompletedRenderTaskResponse.Parameters; + + result: CompletedRenderTaskResponse.Result; + + /** + * The current status of the task. + */ + status: 'completed'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace CompletedRenderTaskResponse { + export interface Parameters { + /** + * Dots per inch (DPI) for the rendered image. Default is 300. + */ + dpi: number; + + /** + * The id of the file to operate on. + */ + input: string; + + /** + * The name of the file + */ + name?: string; + + /** + * Page range (e.g., 2-7), a comma-separated list (e.g., 2,3,7) of pages. + */ + pages?: string; + } + + export interface Result { + generated_files: Array; + } + } + + export interface PendingRenderTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'render'; + + parameters: PendingRenderTaskResponse.Parameters; + + result: unknown; + + /** + * The current status of the task. + */ + status: 'pending'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace PendingRenderTaskResponse { + export interface Parameters { + /** + * Dots per inch (DPI) for the rendered image. Default is 300. + */ + dpi: number; + + /** + * The id of the file to operate on. + */ + input: string; + + /** + * The name of the file + */ + name?: string; + + /** + * Page range (e.g., 2-7), a comma-separated list (e.g., 2,3,7) of pages. + */ + pages?: string; + } + } + + export interface ProcessingRenderTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'render'; + + parameters: ProcessingRenderTaskResponse.Parameters; + + result: unknown; + + /** + * The current status of the task. + */ + status: 'processing'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace ProcessingRenderTaskResponse { + export interface Parameters { + /** + * Dots per inch (DPI) for the rendered image. Default is 300. + */ + dpi: number; + + /** + * The id of the file to operate on. + */ + input: string; + + /** + * The name of the file + */ + name?: string; + + /** + * Page range (e.g., 2-7), a comma-separated list (e.g., 2,3,7) of pages. + */ + pages?: string; + } + } + + export interface FailedRenderTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'render'; + + parameters: FailedRenderTaskResponse.Parameters; + + result: FailedRenderTaskResponse.Result; + + /** + * The current status of the task. + */ + status: 'failed'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace FailedRenderTaskResponse { + export interface Parameters { + /** + * Dots per inch (DPI) for the rendered image. Default is 300. + */ + dpi: number; + + /** + * The id of the file to operate on. + */ + input: string; + + /** + * The name of the file + */ + name?: string; + + /** + * Page range (e.g., 2-7), a comma-separated list (e.g., 2,3,7) of pages. + */ + pages?: string; + } + + export interface Result { + details: Record; + + error: string; + } + } +} + +/** + * The response of an split task + */ +export type Split = + | Split.CompletedSplitTaskResponse + | Split.PendingSplitTaskResponse + | Split.ProcessingSplitTaskResponse + | Split.FailedSplitTaskResponse; + +export namespace Split { + export interface CompletedSplitTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'split'; + + parameters: CompletedSplitTaskResponse.Parameters; + + result: CompletedSplitTaskResponse.Result; + + /** + * The current status of the task. + */ + status: 'completed'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace CompletedSplitTaskResponse { + export interface Parameters { + /** + * The id of the file to operate on. + */ + input: string; + + /** + * The name of the file + */ + name?: string; + } + + export interface Result { + generated_files: Array; + } + } + + export interface PendingSplitTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'split'; + + parameters: PendingSplitTaskResponse.Parameters; + + result: unknown; + + /** + * The current status of the task. + */ + status: 'pending'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace PendingSplitTaskResponse { + export interface Parameters { + /** + * The id of the file to operate on. + */ + input: string; + + /** + * The name of the file + */ + name?: string; + } + } + + export interface ProcessingSplitTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'split'; + + parameters: ProcessingSplitTaskResponse.Parameters; + + result: unknown; + + /** + * The current status of the task. + */ + status: 'processing'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace ProcessingSplitTaskResponse { + export interface Parameters { + /** + * The id of the file to operate on. + */ + input: string; + + /** + * The name of the file + */ + name?: string; + } + } + + export interface FailedSplitTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'split'; + + parameters: FailedSplitTaskResponse.Parameters; + + result: FailedSplitTaskResponse.Result; + + /** + * The current status of the task. + */ + status: 'failed'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace FailedSplitTaskResponse { + export interface Parameters { + /** + * The id of the file to operate on. + */ + input: string; + + /** + * The name of the file + */ + name?: string; + } + + export interface Result { + details: Record; + + error: string; + } + } +} + +export interface PdfOperationExtractPagesParams { + /** + * The id of the file to operate on. + */ + input: string; + + /** + * Page range (e.g., 2-7), a comma-separated list (e.g., 2,3,7) of pages. + */ + pages: string; + + /** + * The name of the file + */ + name?: string; +} + +export interface PdfOperationMergeParams { + /** + * The list of ids of the files to be merged + */ + input: Array; + + /** + * The name of the file + */ + name?: string; +} + +export interface PdfOperationRenderParams { + /** + * The id of the file to operate on. + */ + input: string; + + /** + * Dots per inch (DPI) for the rendered image. Default is 300. + */ + dpi?: number; + + /** + * The name of the file + */ + name?: string; + + /** + * Page range (e.g., 2-7), a comma-separated list (e.g., 2,3,7) of pages. + */ + pages?: string; +} + +export interface PdfOperationSplitParams { + /** + * The id of the file to operate on. + */ + input: string; + + /** + * The name of the file + */ + name?: string; +} + +export declare namespace PdfOperations { + export { + type DocumentFromTask as DocumentFromTask, + type ExtractPages as ExtractPages, + type Merge as Merge, + type Render as Render, + type Split as Split, + type PdfOperationExtractPagesParams as PdfOperationExtractPagesParams, + type PdfOperationMergeParams as PdfOperationMergeParams, + type PdfOperationRenderParams as PdfOperationRenderParams, + type PdfOperationSplitParams as PdfOperationSplitParams, + }; +} diff --git a/src/resources/tasks.ts b/src/resources/tasks.ts new file mode 100644 index 0000000..e68f5b0 --- /dev/null +++ b/src/resources/tasks.ts @@ -0,0 +1,1735 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../core/resource'; +import * as ImageOperationsAPI from './image-operations'; +import * as PdfOperationsAPI from './pdf-operations'; +import { APIPromise } from '../core/api-promise'; +import { RequestOptions } from '../internal/request-options'; +import { path } from '../internal/utils/path'; + +export class Tasks extends APIResource { + /** + * Retrieves the data for a specific task by its ID. + */ + retrieve(id: string, options?: RequestOptions): APIPromise { + return this._client.get(path`/v1/tasks/${id}`, options); + } + + /** + * Retrieves a paginated list of tasks belonging to the authenticated user. + */ + list( + query: TaskListParams | null | undefined = {}, + options?: RequestOptions, + ): APIPromise { + return this._client.get('/v1/tasks', { query, ...options }); + } +} + +/** + * Task response + */ +export type TaskResponse = + | TaskResponse.CompletedApplyEffectTaskResponse + | TaskResponse.PendingApplyEffectTaskResponse + | TaskResponse.ProcessingApplyEffectTaskResponse + | TaskResponse.FailedApplyEffectTaskResponse + | TaskResponse.CompletedConvertTaskResponse + | TaskResponse.PendingConvertTaskResponse + | TaskResponse.ProcessingConvertTaskResponse + | TaskResponse.FailedConvertTaskResponse + | TaskResponse.CompletedConvertTaskResponse + | TaskResponse.PendingConvertTaskResponse + | TaskResponse.ProcessingConvertTaskResponse + | TaskResponse.FailedConvertTaskResponse + | TaskResponse.CompletedExtractTextTaskResponse + | TaskResponse.PendingExtractTextTaskResponse + | TaskResponse.ProcessingExtractTextTaskResponse + | TaskResponse.FailedExtractTextTaskResponse + | TaskResponse.CompletedWarpTaskResponse + | TaskResponse.PendingWarpTaskResponse + | TaskResponse.ProcessingWarpTaskResponse + | TaskResponse.FailedWarpTaskResponse + | TaskResponse.CompletedExtractPagesTaskResponse + | TaskResponse.PendingExtractPagesTaskResponse + | TaskResponse.ProcessingExtractPagesTaskResponse + | TaskResponse.FailedExtractPagesTaskResponse + | TaskResponse.CompletedMergeTaskResponse + | TaskResponse.PendingMergeTaskResponse + | TaskResponse.ProcessingMergeTaskResponse + | TaskResponse.FailedMergeTaskResponse + | TaskResponse.CompletedRenderTaskResponse + | TaskResponse.PendingRenderTaskResponse + | TaskResponse.ProcessingRenderTaskResponse + | TaskResponse.FailedRenderTaskResponse + | TaskResponse.CompletedSplitTaskResponse + | TaskResponse.PendingSplitTaskResponse + | TaskResponse.ProcessingSplitTaskResponse + | TaskResponse.FailedSplitTaskResponse; + +export namespace TaskResponse { + export interface CompletedApplyEffectTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'apply-effect'; + + parameters: CompletedApplyEffectTaskResponse.Parameters; + + result: CompletedApplyEffectTaskResponse.Result; + + /** + * The current status of the task. + */ + status: 'completed'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace CompletedApplyEffectTaskResponse { + export interface Parameters { + /** + * The effect to apply to the image + */ + effect: 'grayscale' | 'scanner' | 'black-background'; + + /** + * The id of the file to operate on. + */ + input: string; + + /** + * The name of the file + */ + name?: string; + } + + export interface Result { + generated_files: Array; + } + } + + export interface PendingApplyEffectTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'apply-effect'; + + parameters: PendingApplyEffectTaskResponse.Parameters; + + result: unknown; + + /** + * The current status of the task. + */ + status: 'pending'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace PendingApplyEffectTaskResponse { + export interface Parameters { + /** + * The effect to apply to the image + */ + effect: 'grayscale' | 'scanner' | 'black-background'; + + /** + * The id of the file to operate on. + */ + input: string; + + /** + * The name of the file + */ + name?: string; + } + } + + export interface ProcessingApplyEffectTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'apply-effect'; + + parameters: ProcessingApplyEffectTaskResponse.Parameters; + + result: unknown; + + /** + * The current status of the task. + */ + status: 'processing'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace ProcessingApplyEffectTaskResponse { + export interface Parameters { + /** + * The effect to apply to the image + */ + effect: 'grayscale' | 'scanner' | 'black-background'; + + /** + * The id of the file to operate on. + */ + input: string; + + /** + * The name of the file + */ + name?: string; + } + } + + export interface FailedApplyEffectTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'apply-effect'; + + parameters: FailedApplyEffectTaskResponse.Parameters; + + result: FailedApplyEffectTaskResponse.Result; + + /** + * The current status of the task. + */ + status: 'failed'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace FailedApplyEffectTaskResponse { + export interface Parameters { + /** + * The effect to apply to the image + */ + effect: 'grayscale' | 'scanner' | 'black-background'; + + /** + * The id of the file to operate on. + */ + input: string; + + /** + * The name of the file + */ + name?: string; + } + + export interface Result { + details: Record; + + error: string; + } + } + + export interface CompletedConvertTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'convert'; + + parameters: ImageOperationsAPI.ConvertRequest; + + result: CompletedConvertTaskResponse.Result; + + /** + * The current status of the task. + */ + status: 'completed'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace CompletedConvertTaskResponse { + export interface Result { + generated_files: Array; + } + } + + export interface PendingConvertTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'convert'; + + parameters: ImageOperationsAPI.ConvertRequest; + + result: unknown; + + /** + * The current status of the task. + */ + status: 'pending'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export interface ProcessingConvertTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'convert'; + + parameters: ImageOperationsAPI.ConvertRequest; + + result: unknown; + + /** + * The current status of the task. + */ + status: 'processing'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export interface FailedConvertTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'convert'; + + parameters: ImageOperationsAPI.ConvertRequest; + + result: FailedConvertTaskResponse.Result; + + /** + * The current status of the task. + */ + status: 'failed'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace FailedConvertTaskResponse { + export interface Result { + details: Record; + + error: string; + } + } + + export interface CompletedConvertTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'convert'; + + parameters: ImageOperationsAPI.ConvertRequest; + + result: CompletedConvertTaskResponse.Result; + + /** + * The current status of the task. + */ + status: 'completed'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace CompletedConvertTaskResponse { + export interface Result { + /** + * The list of documents detected in the image + */ + documents: Array; + } + + export namespace Result { + export interface Document { + /** + * The rectangle that contains the document in the image + */ + bounding_box: ImageOperationsAPI.BoundingBox; + + /** + * The coordinates of the vertex inside the image + */ + vertices: Array; + } + } + } + + export interface PendingConvertTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'convert'; + + parameters: ImageOperationsAPI.ConvertRequest; + + result: unknown; + + /** + * The current status of the task. + */ + status: 'pending'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export interface ProcessingConvertTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'convert'; + + parameters: ImageOperationsAPI.ConvertRequest; + + result: unknown; + + /** + * The current status of the task. + */ + status: 'processing'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export interface FailedConvertTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'convert'; + + parameters: ImageOperationsAPI.ConvertRequest; + + result: FailedConvertTaskResponse.Result; + + /** + * The current status of the task. + */ + status: 'failed'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace FailedConvertTaskResponse { + export interface Result { + details: Record; + + error: string; + } + } + + export interface CompletedExtractTextTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'extract-text'; + + /** + * Extract text from an image in various formats. + */ + parameters: ImageOperationsAPI.ExtractTextRequest; + + result: CompletedExtractTextTaskResponse.Result; + + /** + * The current status of the task. + */ + status: 'completed'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace CompletedExtractTextTaskResponse { + export interface Result { + content: string; + + format: 'plain' | 'markdown' | 'html' | 'json'; + } + } + + export interface PendingExtractTextTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'extract-text'; + + /** + * Extract text from an image in various formats. + */ + parameters: ImageOperationsAPI.ExtractTextRequest; + + result: unknown; + + /** + * The current status of the task. + */ + status: 'pending'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export interface ProcessingExtractTextTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'extract-text'; + + /** + * Extract text from an image in various formats. + */ + parameters: ImageOperationsAPI.ExtractTextRequest; + + result: unknown; + + /** + * The current status of the task. + */ + status: 'processing'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export interface FailedExtractTextTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'extract-text'; + + /** + * Extract text from an image in various formats. + */ + parameters: ImageOperationsAPI.ExtractTextRequest; + + result: FailedExtractTextTaskResponse.Result; + + /** + * The current status of the task. + */ + status: 'failed'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace FailedExtractTextTaskResponse { + export interface Result { + details: Record; + + error: string; + } + } + + export interface CompletedWarpTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'warp'; + + /** + * Transform an image by warping it to a quadrilateral. + */ + parameters: ImageOperationsAPI.WarpRequest; + + result: CompletedWarpTaskResponse.Result; + + /** + * The current status of the task. + */ + status: 'completed'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace CompletedWarpTaskResponse { + export interface Result { + generated_files: Array; + } + } + + export interface PendingWarpTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'warp'; + + /** + * Transform an image by warping it to a quadrilateral. + */ + parameters: ImageOperationsAPI.WarpRequest; + + result: unknown; + + /** + * The current status of the task. + */ + status: 'pending'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export interface ProcessingWarpTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'warp'; + + /** + * Transform an image by warping it to a quadrilateral. + */ + parameters: ImageOperationsAPI.WarpRequest; + + result: unknown; + + /** + * The current status of the task. + */ + status: 'processing'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export interface FailedWarpTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'warp'; + + /** + * Transform an image by warping it to a quadrilateral. + */ + parameters: ImageOperationsAPI.WarpRequest; + + result: FailedWarpTaskResponse.Result; + + /** + * The current status of the task. + */ + status: 'failed'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace FailedWarpTaskResponse { + export interface Result { + details: Record; + + error: string; + } + } + + export interface CompletedExtractPagesTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'extract-pages'; + + parameters: CompletedExtractPagesTaskResponse.Parameters; + + result: CompletedExtractPagesTaskResponse.Result; + + /** + * The current status of the task. + */ + status: 'completed'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace CompletedExtractPagesTaskResponse { + export interface Parameters { + /** + * The id of the file to operate on. + */ + input: string; + + /** + * Page range (e.g., 2-7), a comma-separated list (e.g., 2,3,7) of pages. + */ + pages: string; + + /** + * The name of the file + */ + name?: string; + } + + export interface Result { + generated_files: Array; + } + } + + export interface PendingExtractPagesTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'extract-pages'; + + parameters: PendingExtractPagesTaskResponse.Parameters; + + result: unknown; + + /** + * The current status of the task. + */ + status: 'pending'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace PendingExtractPagesTaskResponse { + export interface Parameters { + /** + * The id of the file to operate on. + */ + input: string; + + /** + * Page range (e.g., 2-7), a comma-separated list (e.g., 2,3,7) of pages. + */ + pages: string; + + /** + * The name of the file + */ + name?: string; + } + } + + export interface ProcessingExtractPagesTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'extract-pages'; + + parameters: ProcessingExtractPagesTaskResponse.Parameters; + + result: unknown; + + /** + * The current status of the task. + */ + status: 'processing'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace ProcessingExtractPagesTaskResponse { + export interface Parameters { + /** + * The id of the file to operate on. + */ + input: string; + + /** + * Page range (e.g., 2-7), a comma-separated list (e.g., 2,3,7) of pages. + */ + pages: string; + + /** + * The name of the file + */ + name?: string; + } + } + + export interface FailedExtractPagesTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'extract-pages'; + + parameters: FailedExtractPagesTaskResponse.Parameters; + + result: FailedExtractPagesTaskResponse.Result; + + /** + * The current status of the task. + */ + status: 'failed'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace FailedExtractPagesTaskResponse { + export interface Parameters { + /** + * The id of the file to operate on. + */ + input: string; + + /** + * Page range (e.g., 2-7), a comma-separated list (e.g., 2,3,7) of pages. + */ + pages: string; + + /** + * The name of the file + */ + name?: string; + } + + export interface Result { + details: Record; + + error: string; + } + } + + export interface CompletedMergeTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'merge'; + + parameters: CompletedMergeTaskResponse.Parameters; + + result: CompletedMergeTaskResponse.Result; + + /** + * The current status of the task. + */ + status: 'completed'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace CompletedMergeTaskResponse { + export interface Parameters { + /** + * The list of ids of the files to be merged + */ + input: Array; + + /** + * The name of the file + */ + name?: string; + } + + export interface Result { + generated_files: Array; + } + } + + export interface PendingMergeTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'merge'; + + parameters: PendingMergeTaskResponse.Parameters; + + result: unknown; + + /** + * The current status of the task. + */ + status: 'pending'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace PendingMergeTaskResponse { + export interface Parameters { + /** + * The list of ids of the files to be merged + */ + input: Array; + + /** + * The name of the file + */ + name?: string; + } + } + + export interface ProcessingMergeTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'merge'; + + parameters: ProcessingMergeTaskResponse.Parameters; + + result: unknown; + + /** + * The current status of the task. + */ + status: 'processing'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace ProcessingMergeTaskResponse { + export interface Parameters { + /** + * The list of ids of the files to be merged + */ + input: Array; + + /** + * The name of the file + */ + name?: string; + } + } + + export interface FailedMergeTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'merge'; + + parameters: FailedMergeTaskResponse.Parameters; + + result: FailedMergeTaskResponse.Result; + + /** + * The current status of the task. + */ + status: 'failed'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace FailedMergeTaskResponse { + export interface Parameters { + /** + * The list of ids of the files to be merged + */ + input: Array; + + /** + * The name of the file + */ + name?: string; + } + + export interface Result { + details: Record; + + error: string; + } + } + + export interface CompletedRenderTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'render'; + + parameters: CompletedRenderTaskResponse.Parameters; + + result: CompletedRenderTaskResponse.Result; + + /** + * The current status of the task. + */ + status: 'completed'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace CompletedRenderTaskResponse { + export interface Parameters { + /** + * Dots per inch (DPI) for the rendered image. Default is 300. + */ + dpi: number; + + /** + * The id of the file to operate on. + */ + input: string; + + /** + * The name of the file + */ + name?: string; + + /** + * Page range (e.g., 2-7), a comma-separated list (e.g., 2,3,7) of pages. + */ + pages?: string; + } + + export interface Result { + generated_files: Array; + } + } + + export interface PendingRenderTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'render'; + + parameters: PendingRenderTaskResponse.Parameters; + + result: unknown; + + /** + * The current status of the task. + */ + status: 'pending'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace PendingRenderTaskResponse { + export interface Parameters { + /** + * Dots per inch (DPI) for the rendered image. Default is 300. + */ + dpi: number; + + /** + * The id of the file to operate on. + */ + input: string; + + /** + * The name of the file + */ + name?: string; + + /** + * Page range (e.g., 2-7), a comma-separated list (e.g., 2,3,7) of pages. + */ + pages?: string; + } + } + + export interface ProcessingRenderTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'render'; + + parameters: ProcessingRenderTaskResponse.Parameters; + + result: unknown; + + /** + * The current status of the task. + */ + status: 'processing'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace ProcessingRenderTaskResponse { + export interface Parameters { + /** + * Dots per inch (DPI) for the rendered image. Default is 300. + */ + dpi: number; + + /** + * The id of the file to operate on. + */ + input: string; + + /** + * The name of the file + */ + name?: string; + + /** + * Page range (e.g., 2-7), a comma-separated list (e.g., 2,3,7) of pages. + */ + pages?: string; + } + } + + export interface FailedRenderTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'render'; + + parameters: FailedRenderTaskResponse.Parameters; + + result: FailedRenderTaskResponse.Result; + + /** + * The current status of the task. + */ + status: 'failed'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace FailedRenderTaskResponse { + export interface Parameters { + /** + * Dots per inch (DPI) for the rendered image. Default is 300. + */ + dpi: number; + + /** + * The id of the file to operate on. + */ + input: string; + + /** + * The name of the file + */ + name?: string; + + /** + * Page range (e.g., 2-7), a comma-separated list (e.g., 2,3,7) of pages. + */ + pages?: string; + } + + export interface Result { + details: Record; + + error: string; + } + } + + export interface CompletedSplitTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'split'; + + parameters: CompletedSplitTaskResponse.Parameters; + + result: CompletedSplitTaskResponse.Result; + + /** + * The current status of the task. + */ + status: 'completed'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace CompletedSplitTaskResponse { + export interface Parameters { + /** + * The id of the file to operate on. + */ + input: string; + + /** + * The name of the file + */ + name?: string; + } + + export interface Result { + generated_files: Array; + } + } + + export interface PendingSplitTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'split'; + + parameters: PendingSplitTaskResponse.Parameters; + + result: unknown; + + /** + * The current status of the task. + */ + status: 'pending'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace PendingSplitTaskResponse { + export interface Parameters { + /** + * The id of the file to operate on. + */ + input: string; + + /** + * The name of the file + */ + name?: string; + } + } + + export interface ProcessingSplitTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'split'; + + parameters: ProcessingSplitTaskResponse.Parameters; + + result: unknown; + + /** + * The current status of the task. + */ + status: 'processing'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace ProcessingSplitTaskResponse { + export interface Parameters { + /** + * The id of the file to operate on. + */ + input: string; + + /** + * The name of the file + */ + name?: string; + } + } + + export interface FailedSplitTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'split'; + + parameters: FailedSplitTaskResponse.Parameters; + + result: FailedSplitTaskResponse.Result; + + /** + * The current status of the task. + */ + status: 'failed'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace FailedSplitTaskResponse { + export interface Parameters { + /** + * The id of the file to operate on. + */ + input: string; + + /** + * The name of the file + */ + name?: string; + } + + export interface Result { + details: Record; + + error: string; + } + } +} + +/** + * Paginated list of tasks + */ +export interface TaskListResponse { + /** + * Array of task responses + */ + data: Array; + + links: TaskListResponse.Links; +} + +export namespace TaskListResponse { + export interface Links { + /** + * Next page link + */ + next: string | null; + + /** + * Previous page link + */ + previous: string | null; + } +} + +export interface TaskListParams { + from?: string; + + take?: number; +} + +export declare namespace Tasks { + export { + type TaskResponse as TaskResponse, + type TaskListResponse as TaskListResponse, + type TaskListParams as TaskListParams, + }; +} diff --git a/src/uploads.ts b/src/uploads.ts new file mode 100644 index 0000000..b2ef647 --- /dev/null +++ b/src/uploads.ts @@ -0,0 +1,2 @@ +/** @deprecated Import from ./core/uploads instead */ +export * from './core/uploads'; diff --git a/src/version.ts b/src/version.ts new file mode 100644 index 0000000..55a1a52 --- /dev/null +++ b/src/version.ts @@ -0,0 +1 @@ +export const VERSION = '0.0.1-alpha.0'; diff --git a/tests/api-resources/events.test.ts b/tests/api-resources/events.test.ts new file mode 100644 index 0000000..dc19fa5 --- /dev/null +++ b/tests/api-resources/events.test.ts @@ -0,0 +1,30 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import ScanDocuments from 'scan-documents'; + +const client = new ScanDocuments({ + apiKey: 'My API Key', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +describe('resource events', () => { + // skipped: tests are disabled for the time being + test.skip('list', async () => { + const responsePromise = client.events.list(); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + // skipped: tests are disabled for the time being + test.skip('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.events.list({ from: 'from', take: 1 }, { path: '/_stainless_unknown_path' }), + ).rejects.toThrow(ScanDocuments.NotFoundError); + }); +}); diff --git a/tests/api-resources/files.test.ts b/tests/api-resources/files.test.ts new file mode 100644 index 0000000..2526df0 --- /dev/null +++ b/tests/api-resources/files.test.ts @@ -0,0 +1,77 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import ScanDocuments, { toFile } from 'scan-documents'; + +const client = new ScanDocuments({ + apiKey: 'My API Key', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +describe('resource files', () => { + // skipped: tests are disabled for the time being + test.skip('retrieve', async () => { + const responsePromise = client.files.retrieve('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); + }); + + // skipped: tests are disabled for the time being + test.skip('list', async () => { + const responsePromise = client.files.list(); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + // skipped: tests are disabled for the time being + test.skip('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.files.list({ from: 'from', take: 1 }, { path: '/_stainless_unknown_path' }), + ).rejects.toThrow(ScanDocuments.NotFoundError); + }); + + // skipped: tests are disabled for the time being + test.skip('delete', async () => { + const responsePromise = client.files.delete('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); + }); + + // skipped: tests are disabled for the time being + test.skip('upload: only required params', async () => { + const responsePromise = client.files.upload({ + file: await toFile(Buffer.from('# my file contents'), 'README.md'), + name: 'File Name', + }); + 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); + }); + + // skipped: tests are disabled for the time being + test.skip('upload: required and optional params', async () => { + const response = await client.files.upload({ + file: await toFile(Buffer.from('# my file contents'), 'README.md'), + name: 'File Name', + }); + }); +}); diff --git a/tests/api-resources/image-operations.test.ts b/tests/api-resources/image-operations.test.ts new file mode 100644 index 0000000..e8f7113 --- /dev/null +++ b/tests/api-resources/image-operations.test.ts @@ -0,0 +1,132 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import ScanDocuments from 'scan-documents'; + +const client = new ScanDocuments({ + apiKey: 'My API Key', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +describe('resource imageOperations', () => { + // skipped: tests are disabled for the time being + test.skip('applyEffect: only required params', async () => { + const responsePromise = client.imageOperations.applyEffect({ + effect: 'grayscale', + input: 'file_avyrvozb9302uwhq', + }); + 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); + }); + + // skipped: tests are disabled for the time being + test.skip('applyEffect: required and optional params', async () => { + const response = await client.imageOperations.applyEffect({ + effect: 'grayscale', + input: 'file_avyrvozb9302uwhq', + name: 'Example Image', + }); + }); + + // skipped: tests are disabled for the time being + test.skip('convert: only required params', async () => { + const responsePromise = client.imageOperations.convert({ + input: 'file_avyrvozb9302uwhq', + target_format: 'image/png', + }); + 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); + }); + + // skipped: tests are disabled for the time being + test.skip('convert: required and optional params', async () => { + const response = await client.imageOperations.convert({ + input: 'file_avyrvozb9302uwhq', + target_format: 'image/png', + name: 'Example Image', + }); + }); + + // skipped: tests are disabled for the time being + test.skip('detectDocuments: only required params', async () => { + const responsePromise = client.imageOperations.detectDocuments({ input: 'file_avyrvozb9302uwhq' }); + 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); + }); + + // skipped: tests are disabled for the time being + test.skip('detectDocuments: required and optional params', async () => { + const response = await client.imageOperations.detectDocuments({ input: 'file_avyrvozb9302uwhq' }); + }); + + // skipped: tests are disabled for the time being + test.skip('extractText: only required params', async () => { + const responsePromise = client.imageOperations.extractText({ + format: 'plain', + input: 'file_avyrvozb9302uwhq', + }); + 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); + }); + + // skipped: tests are disabled for the time being + test.skip('extractText: required and optional params', async () => { + const response = await client.imageOperations.extractText({ + format: 'plain', + input: 'file_avyrvozb9302uwhq', + }); + }); + + // skipped: tests are disabled for the time being + test.skip('warp: only required params', async () => { + const responsePromise = client.imageOperations.warp({ + input: 'file_avyrvozb9302uwhq', + vertices: [ + { x: 0, y: 0 }, + { x: 100, y: 10 }, + { x: 100, y: 100 }, + { x: 0, y: 90 }, + ], + }); + 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); + }); + + // skipped: tests are disabled for the time being + test.skip('warp: required and optional params', async () => { + const response = await client.imageOperations.warp({ + input: 'file_avyrvozb9302uwhq', + vertices: [ + { x: 0, y: 0 }, + { x: 100, y: 10 }, + { x: 100, y: 100 }, + { x: 0, y: 90 }, + ], + name: 'Example Image', + }); + }); +}); diff --git a/tests/api-resources/pdf-operations.test.ts b/tests/api-resources/pdf-operations.test.ts new file mode 100644 index 0000000..f6d050c --- /dev/null +++ b/tests/api-resources/pdf-operations.test.ts @@ -0,0 +1,93 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import ScanDocuments from 'scan-documents'; + +const client = new ScanDocuments({ + apiKey: 'My API Key', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +describe('resource pdfOperations', () => { + // skipped: tests are disabled for the time being + test.skip('extractPages: only required params', async () => { + const responsePromise = client.pdfOperations.extractPages({ + input: 'file_avyrvozb9302uwhq', + pages: '2-7', + }); + 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); + }); + + // skipped: tests are disabled for the time being + test.skip('extractPages: required and optional params', async () => { + const response = await client.pdfOperations.extractPages({ + input: 'file_avyrvozb9302uwhq', + pages: '2-7', + name: 'File Name', + }); + }); + + // skipped: tests are disabled for the time being + test.skip('merge: only required params', async () => { + const responsePromise = client.pdfOperations.merge({ input: ['file_avyrvozb9302uwhq'] }); + 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); + }); + + // skipped: tests are disabled for the time being + test.skip('merge: required and optional params', async () => { + const response = await client.pdfOperations.merge({ + input: ['file_avyrvozb9302uwhq'], + name: 'File Name', + }); + }); + + // skipped: tests are disabled for the time being + test.skip('render: only required params', async () => { + const responsePromise = client.pdfOperations.render({ input: 'file_avyrvozb9302uwhq' }); + 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); + }); + + // skipped: tests are disabled for the time being + test.skip('render: required and optional params', async () => { + const response = await client.pdfOperations.render({ + input: 'file_avyrvozb9302uwhq', + dpi: 300, + name: 'File Name', + pages: '2-7', + }); + }); + + // skipped: tests are disabled for the time being + test.skip('split: only required params', async () => { + const responsePromise = client.pdfOperations.split({ input: 'file_avyrvozb9302uwhq' }); + 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); + }); + + // skipped: tests are disabled for the time being + test.skip('split: required and optional params', async () => { + const response = await client.pdfOperations.split({ input: 'file_avyrvozb9302uwhq', name: 'File Name' }); + }); +}); diff --git a/tests/api-resources/tasks.test.ts b/tests/api-resources/tasks.test.ts new file mode 100644 index 0000000..d935f79 --- /dev/null +++ b/tests/api-resources/tasks.test.ts @@ -0,0 +1,42 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import ScanDocuments from 'scan-documents'; + +const client = new ScanDocuments({ + apiKey: 'My API Key', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +describe('resource tasks', () => { + // skipped: tests are disabled for the time being + test.skip('retrieve', async () => { + const responsePromise = client.tasks.retrieve('task_euyrvozb9302uwhq'); + 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); + }); + + // skipped: tests are disabled for the time being + test.skip('list', async () => { + const responsePromise = client.tasks.list(); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + // skipped: tests are disabled for the time being + test.skip('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.tasks.list({ from: 'from', take: 1 }, { path: '/_stainless_unknown_path' }), + ).rejects.toThrow(ScanDocuments.NotFoundError); + }); +}); diff --git a/tests/base64.test.ts b/tests/base64.test.ts new file mode 100644 index 0000000..489012f --- /dev/null +++ b/tests/base64.test.ts @@ -0,0 +1,80 @@ +import { fromBase64, toBase64 } from 'scan-documents/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 0000000..34e6395 --- /dev/null +++ b/tests/buildHeaders.test.ts @@ -0,0 +1,88 @@ +import { inspect } from 'node:util'; +import { buildHeaders, type HeadersLike, type NullableHeaders } from 'scan-documents/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 new file mode 100644 index 0000000..317de3c --- /dev/null +++ b/tests/form.test.ts @@ -0,0 +1,85 @@ +import { multipartFormRequestOptions, createForm } from 'scan-documents/internal/uploads'; +import { toFile } from 'scan-documents/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' }), + }, + }, + fetch, + ); + }); + + test('null', async () => { + await expect(() => + multipartFormRequestOptions( + { + body: { + null: null, + }, + }, + fetch, + ), + ).rejects.toThrow(TypeError); + }); + + test('undefined is stripped', async () => { + 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, + }, + }, + fetch, + ); + expect(Array.from(form.entries())).toEqual([]); + + 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], + }, + fetch, + ); + expect(Array.from(form.entries())).toEqual([]); + + const form2 = await createForm( + { + bar: [undefined, 'foo'], + }, + fetch, + ); + expect(Array.from(form2.entries())).toEqual([['bar[]', 'foo']]); + }); +}); diff --git a/tests/index.test.ts b/tests/index.test.ts new file mode 100644 index 0000000..54da281 --- /dev/null +++ b/tests/index.test.ts @@ -0,0 +1,718 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIPromise } from 'scan-documents/core/api-promise'; + +import util from 'node:util'; +import ScanDocuments from 'scan-documents'; +import { APIUserAbortError } from 'scan-documents'; +const defaultFetch = fetch; + +describe('instantiate client', () => { + const env = process.env; + + beforeEach(() => { + jest.resetModules(); + process.env = { ...env }; + }); + + afterEach(() => { + process.env = env; + }); + + describe('defaultHeaders', () => { + const client = new ScanDocuments({ + baseURL: 'http://localhost:5000/', + defaultHeaders: { 'X-My-Default-Header': '2' }, + apiKey: 'My API Key', + }); + + test('they are used in the request', () => { + const { req } = client.buildRequest({ path: '/foo', method: 'post' }); + expect(req.headers.get('x-my-default-header')).toEqual('2'); + }); + + test('can ignore `undefined` and leave the default', () => { + const { req } = client.buildRequest({ + path: '/foo', + method: 'post', + headers: { 'X-My-Default-Header': undefined }, + }); + expect(req.headers.get('x-my-default-header')).toEqual('2'); + }); + + test('can be removed with `null`', () => { + const { req } = client.buildRequest({ + path: '/foo', + method: 'post', + headers: { 'X-My-Default-Header': null }, + }); + expect(req.headers.has('x-my-default-header')).toBe(false); + }); + }); + describe('logging', () => { + const env = process.env; + + beforeEach(() => { + process.env = { ...env }; + process.env['SCAN_DOCUMENTS_LOG'] = undefined; + }); + + afterEach(() => { + process.env = env; + }); + + const forceAPIResponseForClient = async (client: ScanDocuments) => { + 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 ScanDocuments({ logger: logger, logLevel: 'debug', apiKey: 'My API Key' }); + + await forceAPIResponseForClient(client); + expect(debugMock).toHaveBeenCalled(); + }); + + test('default logLevel is warn', async () => { + const client = new ScanDocuments({ 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 ScanDocuments({ 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['SCAN_DOCUMENTS_LOG'] = 'debug'; + const client = new ScanDocuments({ 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['SCAN_DOCUMENTS_LOG'] = 'not a log level'; + const client = new ScanDocuments({ logger: logger, apiKey: 'My API Key' }); + expect(client.logLevel).toBe('warn'); + expect(warnMock).toHaveBeenCalledWith( + 'process.env[\'SCAN_DOCUMENTS_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['SCAN_DOCUMENTS_LOG'] = 'debug'; + const client = new ScanDocuments({ 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['SCAN_DOCUMENTS_LOG'] = 'not a log level'; + const client = new ScanDocuments({ logger: logger, logLevel: 'debug', apiKey: 'My API Key' }); + expect(client.logLevel).toBe('debug'); + expect(warnMock).not.toHaveBeenCalled(); + }); + }); + + describe('defaultQuery', () => { + test('with null query params given', () => { + const client = new ScanDocuments({ + baseURL: 'http://localhost:5000/', + defaultQuery: { apiVersion: 'foo' }, + apiKey: 'My API Key', + }); + expect(client.buildURL('/foo', null)).toEqual('http://localhost:5000/foo?apiVersion=foo'); + }); + + test('multiple default query params', () => { + const client = new ScanDocuments({ + baseURL: 'http://localhost:5000/', + defaultQuery: { apiVersion: 'foo', hello: 'world' }, + apiKey: 'My API Key', + }); + expect(client.buildURL('/foo', null)).toEqual('http://localhost:5000/foo?apiVersion=foo&hello=world'); + }); + + test('overriding with `undefined`', () => { + const client = new ScanDocuments({ + baseURL: 'http://localhost:5000/', + defaultQuery: { hello: 'world' }, + apiKey: 'My API Key', + }); + expect(client.buildURL('/foo', { hello: undefined })).toEqual('http://localhost:5000/foo'); + }); + }); + + test('custom fetch', async () => { + const client = new ScanDocuments({ + baseURL: 'http://localhost:5000/', + apiKey: 'My API Key', + fetch: (url) => { + return Promise.resolve( + new Response(JSON.stringify({ url, custom: true }), { + headers: { 'Content-Type': 'application/json' }, + }), + ); + }, + }); + + const response = await client.get('/foo'); + expect(response).toEqual({ url: 'http://localhost:5000/foo', custom: true }); + }); + + test('explicit global fetch', async () => { + // make sure the global fetch type is assignable to our Fetch type + const client = new ScanDocuments({ + baseURL: 'http://localhost:5000/', + apiKey: 'My API Key', + fetch: defaultFetch, + }); + }); + + test('custom signal', async () => { + const client = new ScanDocuments({ + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', + apiKey: 'My API Key', + fetch: (...args) => { + return new Promise((resolve, reject) => + setTimeout( + () => + defaultFetch(...args) + .then(resolve) + .catch(reject), + 300, + ), + ); + }, + }); + + const controller = new AbortController(); + setTimeout(() => controller.abort(), 200); + + const spy = jest.spyOn(client, 'request'); + + await expect(client.get('/foo', { signal: controller.signal })).rejects.toThrowError(APIUserAbortError); + expect(spy).toHaveBeenCalledTimes(1); + }); + + test('normalized method', async () => { + let capturedRequest: RequestInit | undefined; + const testFetch = async (url: string | URL | Request, init: RequestInit = {}): Promise => { + capturedRequest = init; + return new Response(JSON.stringify({}), { headers: { 'Content-Type': 'application/json' } }); + }; + + const client = new ScanDocuments({ + baseURL: 'http://localhost:5000/', + apiKey: 'My API Key', + fetch: testFetch, + }); + + await client.patch('/foo'); + expect(capturedRequest?.method).toEqual('PATCH'); + }); + + describe('baseUrl', () => { + test('trailing slash', () => { + const client = new ScanDocuments({ + baseURL: 'http://localhost:5000/custom/path/', + apiKey: 'My API Key', + }); + expect(client.buildURL('/foo', null)).toEqual('http://localhost:5000/custom/path/foo'); + }); + + test('no trailing slash', () => { + const client = new ScanDocuments({ + baseURL: 'http://localhost:5000/custom/path', + apiKey: 'My API Key', + }); + expect(client.buildURL('/foo', null)).toEqual('http://localhost:5000/custom/path/foo'); + }); + + afterEach(() => { + process.env['SCAN_DOCUMENTS_BASE_URL'] = undefined; + }); + + test('explicit option', () => { + const client = new ScanDocuments({ baseURL: 'https://example.com', apiKey: 'My API Key' }); + expect(client.baseURL).toEqual('https://example.com'); + }); + + test('env variable', () => { + process.env['SCAN_DOCUMENTS_BASE_URL'] = 'https://example.com/from_env'; + const client = new ScanDocuments({ apiKey: 'My API Key' }); + expect(client.baseURL).toEqual('https://example.com/from_env'); + }); + + test('empty env variable', () => { + process.env['SCAN_DOCUMENTS_BASE_URL'] = ''; // empty + const client = new ScanDocuments({ apiKey: 'My API Key' }); + expect(client.baseURL).toEqual('https://api.scan-documents.com'); + }); + + test('blank env variable', () => { + process.env['SCAN_DOCUMENTS_BASE_URL'] = ' '; // blank + const client = new ScanDocuments({ apiKey: 'My API Key' }); + expect(client.baseURL).toEqual('https://api.scan-documents.com'); + }); + }); + + test('maxRetries option is correctly set', () => { + const client = new ScanDocuments({ maxRetries: 4, apiKey: 'My API Key' }); + expect(client.maxRetries).toEqual(4); + + // default + const client2 = new ScanDocuments({ apiKey: 'My API Key' }); + expect(client2.maxRetries).toEqual(2); + }); + + describe('withOptions', () => { + test('creates a new client with overridden options', () => { + const client = new ScanDocuments({ + 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 ScanDocuments({ + 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 ScanDocuments({ + 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['SCAN_DOCUMENTS_API_KEY'] = 'My API Key'; + const client = new ScanDocuments(); + expect(client.apiKey).toBe('My API Key'); + }); + + test('with overridden environment variable arguments', () => { + // set options via env var + process.env['SCAN_DOCUMENTS_API_KEY'] = 'another My API Key'; + const client = new ScanDocuments({ apiKey: 'My API Key' }); + expect(client.apiKey).toBe('My API Key'); + }); +}); + +describe('request building', () => { + const client = new ScanDocuments({ apiKey: 'My API Key' }); + + describe('custom headers', () => { + test('handles undefined', () => { + const { req } = client.buildRequest({ + path: '/foo', + method: 'post', + body: { value: 'hello' }, + headers: { 'X-Foo': 'baz', 'x-foo': 'bar', 'x-Foo': undefined, 'x-baz': 'bam', 'X-Baz': null }, + }); + 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 ScanDocuments({ 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: string | URL | Request, + { signal }: RequestInit = {}, + ): Promise => { + if (count++ === 0) { + return new Promise( + (resolve, reject) => signal?.addEventListener('abort', () => reject(new Error('timed out'))), + ); + } + return new Response(JSON.stringify({ a: 1 }), { headers: { 'Content-Type': 'application/json' } }); + }; + + const client = new ScanDocuments({ apiKey: 'My API Key', timeout: 10, fetch: testFetch }); + + expect(await client.request({ path: '/foo', method: 'get' })).toEqual({ a: 1 }); + expect(count).toEqual(2); + expect( + await client + .request({ path: '/foo', method: 'get' }) + .asResponse() + .then((r) => r.text()), + ).toEqual(JSON.stringify({ a: 1 })); + expect(count).toEqual(3); + }); + + test('retry count header', async () => { + let count = 0; + let capturedRequest: RequestInit | undefined; + const testFetch = async (url: string | URL | Request, init: RequestInit = {}): Promise => { + count++; + if (count <= 2) { + return new Response(undefined, { + status: 429, + headers: { + 'Retry-After': '0.1', + }, + }); + } + capturedRequest = init; + return new Response(JSON.stringify({ a: 1 }), { headers: { 'Content-Type': 'application/json' } }); + }; + + const client = new ScanDocuments({ apiKey: 'My API Key', fetch: testFetch, maxRetries: 4 }); + + expect(await client.request({ path: '/foo', method: 'get' })).toEqual({ a: 1 }); + + 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: string | URL | Request, init: RequestInit = {}): Promise => { + count++; + if (count <= 2) { + return new Response(undefined, { + status: 429, + headers: { + 'Retry-After': '0.1', + }, + }); + } + capturedRequest = init; + return new Response(JSON.stringify({ a: 1 }), { headers: { 'Content-Type': 'application/json' } }); + }; + const client = new ScanDocuments({ apiKey: 'My API Key', fetch: testFetch, maxRetries: 4 }); + + expect( + await client.request({ + path: '/foo', + method: 'get', + headers: { 'X-Stainless-Retry-Count': null }, + }), + ).toEqual({ a: 1 }); + + 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: string | URL | Request, init: RequestInit = {}): Promise => { + count++; + if (count <= 2) { + return new Response(undefined, { + status: 429, + headers: { + 'Retry-After': '0.1', + }, + }); + } + capturedRequest = init; + return new Response(JSON.stringify({ a: 1 }), { headers: { 'Content-Type': 'application/json' } }); + }; + const client = new ScanDocuments({ + apiKey: 'My API Key', + fetch: testFetch, + maxRetries: 4, + defaultHeaders: { 'X-Stainless-Retry-Count': null }, + }); + + expect( + await client.request({ + path: '/foo', + method: 'get', + }), + ).toEqual({ a: 1 }); + + expect(capturedRequest!.headers as Headers).not.toHaveProperty('x-stainless-retry-count'); + }); + + test('overwrite retry count header', async () => { + let count = 0; + let capturedRequest: RequestInit | undefined; + const testFetch = async (url: string | URL | Request, init: RequestInit = {}): Promise => { + count++; + if (count <= 2) { + return new Response(undefined, { + status: 429, + headers: { + 'Retry-After': '0.1', + }, + }); + } + capturedRequest = init; + return new Response(JSON.stringify({ a: 1 }), { headers: { 'Content-Type': 'application/json' } }); + }; + const client = new ScanDocuments({ apiKey: 'My API Key', fetch: testFetch, maxRetries: 4 }); + + expect( + await client.request({ + path: '/foo', + method: 'get', + headers: { 'X-Stainless-Retry-Count': '42' }, + }), + ).toEqual({ a: 1 }); + + 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: string | URL | Request, + { signal }: RequestInit = {}, + ): Promise => { + if (count++ === 0) { + return new Response(undefined, { + status: 429, + headers: { + 'Retry-After': '0.1', + }, + }); + } + return new Response(JSON.stringify({ a: 1 }), { headers: { 'Content-Type': 'application/json' } }); + }; + + const client = new ScanDocuments({ apiKey: 'My API Key', fetch: testFetch }); + + expect(await client.request({ path: '/foo', method: 'get' })).toEqual({ a: 1 }); + expect(count).toEqual(2); + expect( + await client + .request({ path: '/foo', method: 'get' }) + .asResponse() + .then((r) => r.text()), + ).toEqual(JSON.stringify({ a: 1 })); + expect(count).toEqual(3); + }); + + test('retry on 429 with retry-after-ms', async () => { + let count = 0; + const testFetch = async ( + url: string | URL | Request, + { signal }: RequestInit = {}, + ): Promise => { + if (count++ === 0) { + return new Response(undefined, { + status: 429, + headers: { + 'Retry-After-Ms': '10', + }, + }); + } + return new Response(JSON.stringify({ a: 1 }), { headers: { 'Content-Type': 'application/json' } }); + }; + + const client = new ScanDocuments({ apiKey: 'My API Key', fetch: testFetch }); + + expect(await client.request({ path: '/foo', method: 'get' })).toEqual({ a: 1 }); + expect(count).toEqual(2); + expect( + await client + .request({ path: '/foo', method: 'get' }) + .asResponse() + .then((r) => r.text()), + ).toEqual(JSON.stringify({ a: 1 })); + expect(count).toEqual(3); + }); +}); diff --git a/tests/path.test.ts b/tests/path.test.ts new file mode 100644 index 0000000..096bc58 --- /dev/null +++ b/tests/path.test.ts @@ -0,0 +1,318 @@ +import { createPathTagFunction, encodeURIPath } from 'scan-documents/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/stringifyQuery.test.ts b/tests/stringifyQuery.test.ts new file mode 100644 index 0000000..0e0f410 --- /dev/null +++ b/tests/stringifyQuery.test.ts @@ -0,0 +1,29 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { ScanDocuments } from 'scan-documents'; + +const { stringifyQuery } = ScanDocuments.prototype as any; + +describe(stringifyQuery, () => { + for (const [input, expected] of [ + [{ a: '1', b: 2, c: true }, 'a=1&b=2&c=true'], + [{ a: null, b: false, c: undefined }, 'a=&b=false'], + [{ 'a/b': 1.28341 }, `${encodeURIComponent('a/b')}=1.28341`], + [ + { 'a/b': 'c/d', 'e=f': 'g&h' }, + `${encodeURIComponent('a/b')}=${encodeURIComponent('c/d')}&${encodeURIComponent( + 'e=f', + )}=${encodeURIComponent('g&h')}`, + ], + ]) { + it(`${JSON.stringify(input)} -> ${expected}`, () => { + expect(stringifyQuery(input)).toEqual(expected); + }); + } + + for (const value of [[], {}, new Date()]) { + it(`${JSON.stringify(value)} -> `, () => { + expect(() => stringifyQuery({ value })).toThrow(`Cannot stringify type ${typeof value}`); + }); + } +}); diff --git a/tests/uploads.test.ts b/tests/uploads.test.ts new file mode 100644 index 0000000..2522d90 --- /dev/null +++ b/tests/uploads.test.ts @@ -0,0 +1,107 @@ +import fs from 'fs'; +import type { ResponseLike } from 'scan-documents/internal/to-file'; +import { toFile } from 'scan-documents/core/uploads'; +import { File } from 'node:buffer'; + +class MyClass { + name: string = 'foo'; +} + +function mockResponse({ url, content }: { url: string; content?: Blob }): ResponseLike { + return { + url, + blob: async () => content || new Blob([]), + }; +} + +describe('toFile', () => { + it('throws a helpful error for mismatched types', async () => { + await expect( + // @ts-expect-error intentionally mismatched type + toFile({ foo: 'string' }), + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"Unexpected data type: object; constructor: Object; props: ["foo"]"`, + ); + + await expect( + // @ts-expect-error intentionally mismatched type + toFile(new MyClass()), + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"Unexpected data type: object; constructor: MyClass; props: ["name"]"`, + ); + }); + + it('disallows string at the type-level', async () => { + // @ts-expect-error we intentionally do not type support for `string` + // to help people avoid passing a file path + const file = await toFile('contents'); + expect(file.text()).resolves.toEqual('contents'); + }); + + it('extracts a file name from a Response', async () => { + const response = mockResponse({ url: 'https://example.com/my/audio.mp3' }); + const file = await toFile(response); + expect(file.name).toEqual('audio.mp3'); + }); + + it('extracts a file name from a File', async () => { + const input = new File(['foo'], 'input.jsonl'); + const file = await toFile(input); + expect(file.name).toEqual('input.jsonl'); + }); + + it('extracts a file name from a ReadStream', async () => { + const input = fs.createReadStream('tests/uploads.test.ts'); + const file = await toFile(input); + expect(file.name).toEqual('uploads.test.ts'); + }); + + it('does not copy File objects', async () => { + const input = new File(['foo'], 'input.jsonl', { type: 'jsonl' }); + const file = await toFile(input); + expect(file).toBe(input); + 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('scan-documents/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/tsc-multi.json b/tsc-multi.json new file mode 100644 index 0000000..170bac7 --- /dev/null +++ b/tsc-multi.json @@ -0,0 +1,7 @@ +{ + "targets": [ + { "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 new file mode 100644 index 0000000..19e20ba --- /dev/null +++ b/tsconfig.build.json @@ -0,0 +1,18 @@ +{ + "extends": "./tsconfig.json", + "include": ["dist/src"], + "exclude": [], + "compilerOptions": { + "rootDir": "./dist/src", + "paths": { + "scan-documents/*": ["dist/src/*"], + "scan-documents": ["dist/src/index.ts"] + }, + "noEmit": false, + "declaration": true, + "declarationMap": true, + "outDir": "dist", + "pretty": true, + "sourceMap": true + } +} diff --git a/tsconfig.deno.json b/tsconfig.deno.json new file mode 100644 index 0000000..849e070 --- /dev/null +++ b/tsconfig.deno.json @@ -0,0 +1,15 @@ +{ + "extends": "./tsconfig.json", + "include": ["dist-deno"], + "exclude": [], + "compilerOptions": { + "rootDir": "./dist-deno", + "lib": ["es2020", "DOM"], + "noEmit": true, + "declaration": true, + "declarationMap": true, + "outDir": "dist-deno", + "pretty": true, + "sourceMap": true + } +} diff --git a/tsconfig.dist-src.json b/tsconfig.dist-src.json new file mode 100644 index 0000000..c550e29 --- /dev/null +++ b/tsconfig.dist-src.json @@ -0,0 +1,11 @@ +{ + // this config is included in the published src directory to prevent TS errors + // from appearing when users go to source, and VSCode opens the source .ts file + // via declaration maps + "include": ["index.ts"], + "compilerOptions": { + "target": "ES2015", + "lib": ["DOM", "DOM.Iterable", "ES2018"], + "moduleResolution": "node" + } +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..488761e --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,38 @@ +{ + "include": ["src", "tests", "examples"], + "exclude": [], + "compilerOptions": { + "target": "es2020", + "lib": ["es2020"], + "module": "commonjs", + "moduleResolution": "node", + "esModuleInterop": true, + "baseUrl": "./", + "paths": { + "scan-documents/*": ["src/*"], + "scan-documents": ["src/index.ts"] + }, + "noEmit": true, + + "resolveJsonModule": true, + + "forceConsistentCasingInFileNames": true, + + "strict": true, + "noImplicitAny": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "strictBindCallApply": true, + "strictPropertyInitialization": true, + "noImplicitThis": true, + "noImplicitReturns": true, + "alwaysStrict": true, + "exactOptionalPropertyTypes": true, + "noUncheckedIndexedAccess": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "isolatedModules": false, + + "skipLibCheck": true + } +} diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000..43da555 --- /dev/null +++ b/yarn.lock @@ -0,0 +1,3506 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@aashutoshrathi/word-wrap@^1.2.3": + version "1.2.6" + resolved "https://registry.yarnpkg.com/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz#bd9154aec9983f77b3a034ecaa015c2e4201f6cf" + integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA== + +"@ampproject/remapping@^2.2.0": + version "2.2.1" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.1.tgz#99e8e11851128b8702cd57c33684f1d0f260b630" + integrity sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg== + dependencies: + "@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" + integrity sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA== + dependencies: + "@babel/highlight" "^7.23.4" + chalk "^2.4.2" + +"@babel/compat-data@^7.23.5": + version "7.23.5" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.23.5.tgz#ffb878728bb6bdcb6f4510aa51b1be9afb8cfd98" + integrity sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw== + +"@babel/core@^7.11.6", "@babel/core@^7.12.3": + version "7.23.6" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.23.6.tgz#8be77cd77c55baadcc1eae1c33df90ab6d2151d4" + integrity sha512-FxpRyGjrMJXh7X3wGLGhNDCRiwpWEF74sKjTLDJSG5Kyvow3QZaG0Adbqzi9ZrVjTWpsX+2cxWXD71NMg93kdw== + dependencies: + "@ampproject/remapping" "^2.2.0" + "@babel/code-frame" "^7.23.5" + "@babel/generator" "^7.23.6" + "@babel/helper-compilation-targets" "^7.23.6" + "@babel/helper-module-transforms" "^7.23.3" + "@babel/helpers" "^7.23.6" + "@babel/parser" "^7.23.6" + "@babel/template" "^7.22.15" + "@babel/traverse" "^7.23.6" + "@babel/types" "^7.23.6" + convert-source-map "^2.0.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.3" + semver "^6.3.1" + +"@babel/generator@^7.23.6", "@babel/generator@^7.7.2": + version "7.23.6" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.6.tgz#9e1fca4811c77a10580d17d26b57b036133f3c2e" + integrity sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw== + dependencies: + "@babel/types" "^7.23.6" + "@jridgewell/gen-mapping" "^0.3.2" + "@jridgewell/trace-mapping" "^0.3.17" + jsesc "^2.5.1" + +"@babel/helper-compilation-targets@^7.23.6": + version "7.23.6" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz#4d79069b16cbcf1461289eccfbbd81501ae39991" + integrity sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ== + dependencies: + "@babel/compat-data" "^7.23.5" + "@babel/helper-validator-option" "^7.23.5" + browserslist "^4.22.2" + lru-cache "^5.1.1" + semver "^6.3.1" + +"@babel/helper-environment-visitor@^7.22.20": + version "7.22.20" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167" + integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA== + +"@babel/helper-function-name@^7.23.0": + version "7.23.0" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz#1f9a3cdbd5b2698a670c30d2735f9af95ed52759" + integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw== + dependencies: + "@babel/template" "^7.22.15" + "@babel/types" "^7.23.0" + +"@babel/helper-hoist-variables@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb" + integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-module-imports@^7.22.15": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz#16146307acdc40cc00c3b2c647713076464bdbf0" + integrity sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w== + dependencies: + "@babel/types" "^7.22.15" + +"@babel/helper-module-transforms@^7.23.3": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz#d7d12c3c5d30af5b3c0fcab2a6d5217773e2d0f1" + integrity sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ== + dependencies: + "@babel/helper-environment-visitor" "^7.22.20" + "@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.20" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.22.5", "@babel/helper-plugin-utils@^7.8.0": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz#dd7ee3735e8a313b9f7b05a773d892e88e6d7295" + integrity sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg== + +"@babel/helper-simple-access@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz#4938357dc7d782b80ed6dbb03a0fba3d22b1d5de" + integrity sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-split-export-declaration@^7.22.6": + version "7.22.6" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c" + integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-string-parser@^7.23.4": + version "7.23.4" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz#9478c707febcbbe1ddb38a3d91a2e054ae622d83" + integrity sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ== + +"@babel/helper-validator-identifier@^7.22.20": + version "7.22.20" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0" + integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A== + +"@babel/helper-validator-option@^7.23.5": + version "7.23.5" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz#907a3fbd4523426285365d1206c423c4c5520307" + integrity sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw== + +"@babel/helpers@^7.23.6": + version "7.23.6" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.23.6.tgz#d03af2ee5fb34691eec0cda90f5ecbb4d4da145a" + integrity sha512-wCfsbN4nBidDRhpDhvcKlzHWCTlgJYUUdSJfzXb2NuBssDSIjc3xcb+znA7l+zYsFljAcGM0aFkN40cR3lXiGA== + dependencies: + "@babel/template" "^7.22.15" + "@babel/traverse" "^7.23.6" + "@babel/types" "^7.23.6" + +"@babel/highlight@^7.23.4": + version "7.23.4" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.23.4.tgz#edaadf4d8232e1a961432db785091207ead0621b" + integrity sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A== + dependencies: + "@babel/helper-validator-identifier" "^7.22.20" + chalk "^2.4.2" + js-tokens "^4.0.0" + +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.22.15", "@babel/parser@^7.23.6": + version "7.23.6" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.6.tgz#ba1c9e512bda72a47e285ae42aff9d2a635a9e3b" + integrity sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ== + +"@babel/plugin-syntax-async-generators@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-bigint@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea" + integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-class-properties@^7.8.3": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" + integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" + +"@babel/plugin-syntax-import-meta@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" + integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-json-strings@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-jsx@^7.7.2": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.23.3.tgz#8f2e4f8a9b5f9aa16067e142c1ac9cd9f810f473" + integrity sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-syntax-logical-assignment-operators@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" + integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-numeric-separator@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" + integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-object-rest-spread@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-chaining@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-top-level-await@^7.8.3": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" + integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-typescript@^7.7.2": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.23.3.tgz#24f460c85dbbc983cd2b9c4994178bcc01df958f" + integrity sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/template@^7.22.15", "@babel/template@^7.3.3": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.15.tgz#09576efc3830f0430f4548ef971dde1350ef2f38" + integrity sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w== + dependencies: + "@babel/code-frame" "^7.22.13" + "@babel/parser" "^7.22.15" + "@babel/types" "^7.22.15" + +"@babel/traverse@^7.23.6": + version "7.23.6" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.6.tgz#b53526a2367a0dd6edc423637f3d2d0f2521abc5" + integrity sha512-czastdK1e8YByZqezMPFiZ8ahwVMh/ESl9vPgvgdB9AmFMGP5jfpFax74AQgl5zj4XHzqeYAg2l8PuUeRS1MgQ== + dependencies: + "@babel/code-frame" "^7.23.5" + "@babel/generator" "^7.23.6" + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-function-name" "^7.23.0" + "@babel/helper-hoist-variables" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + "@babel/parser" "^7.23.6" + "@babel/types" "^7.23.6" + debug "^4.3.1" + globals "^11.1.0" + +"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.22.15", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.23.6", "@babel/types@^7.3.3": + version "7.23.6" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.6.tgz#be33fdb151e1f5a56877d704492c240fc71c7ccd" + integrity sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg== + dependencies: + "@babel/helper-string-parser" "^7.23.4" + "@babel/helper-validator-identifier" "^7.22.20" + to-fast-properties "^2.0.0" + +"@bcoe/v8-coverage@^0.2.3": + version "0.2.3" + 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" + integrity sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg== + +"@cspotcode/source-map-support@0.7.0": + version "0.7.0" + resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz#4789840aa859e46d2f3173727ab707c66bf344f5" + integrity sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA== + dependencies: + "@cspotcode/source-map-consumer" "0.8.0" + +"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": + version "4.4.0" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" + integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== + dependencies: + eslint-visitor-keys "^3.3.0" + +"@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/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/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 "^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@9.20.0": + version "9.20.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.20.0.tgz#7421bcbe74889fcd65d1be59f00130c289856eb4" + integrity sha512-iZA07H9io9Wn836aVTytRaNqh00Sad+EamwOVJT12GTLw1VGMFV/4JaME+JjLtr9fiGaoWgYnS54wrfWsSs4oQ== + +"@eslint/object-schema@^2.1.6": + version "2.1.6" + resolved "https://registry.yarnpkg.com/@eslint/object-schema/-/object-schema-2.1.6.tgz#58369ab5b5b3ca117880c0f6c0b0f32f6950f24f" + integrity sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA== + +"@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: + "@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/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" + resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" + integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== + dependencies: + camelcase "^5.3.1" + find-up "^4.1.0" + get-package-type "^0.1.0" + js-yaml "^3.13.1" + resolve-from "^5.0.0" + +"@istanbuljs/schema@^0.1.2": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" + integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== + +"@jest/console@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-29.7.0.tgz#cd4822dbdb84529265c5a2bdb529a3c9cc950ffc" + integrity sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg== + dependencies: + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + slash "^3.0.0" + +"@jest/core@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-29.7.0.tgz#b6cccc239f30ff36609658c5a5e2291757ce448f" + integrity sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg== + dependencies: + "@jest/console" "^29.7.0" + "@jest/reporters" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + ci-info "^3.2.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + jest-changed-files "^29.7.0" + jest-config "^29.7.0" + jest-haste-map "^29.7.0" + jest-message-util "^29.7.0" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-resolve-dependencies "^29.7.0" + jest-runner "^29.7.0" + jest-runtime "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" + jest-watcher "^29.7.0" + micromatch "^4.0.4" + pretty-format "^29.7.0" + slash "^3.0.0" + strip-ansi "^6.0.0" + +"@jest/create-cache-key-function@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/create-cache-key-function/-/create-cache-key-function-29.7.0.tgz#793be38148fab78e65f40ae30c36785f4ad859f0" + integrity sha512-4QqS3LY5PBmTRHj9sAg1HLoPzqAI0uOX6wI/TRqHIcOxlFidy6YEmCQJk6FSZjNLGCeubDMfmkWL+qaLKhSGQA== + dependencies: + "@jest/types" "^29.6.3" + +"@jest/environment@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-29.7.0.tgz#24d61f54ff1f786f3cd4073b4b94416383baf2a7" + integrity sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw== + dependencies: + "@jest/fake-timers" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + jest-mock "^29.7.0" + +"@jest/expect-utils@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.7.0.tgz#023efe5d26a8a70f21677d0a1afc0f0a44e3a1c6" + integrity sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA== + dependencies: + jest-get-type "^29.6.3" + +"@jest/expect@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-29.7.0.tgz#76a3edb0cb753b70dfbfe23283510d3d45432bf2" + integrity sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ== + dependencies: + expect "^29.7.0" + jest-snapshot "^29.7.0" + +"@jest/fake-timers@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-29.7.0.tgz#fd91bf1fffb16d7d0d24a426ab1a47a49881a565" + integrity sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ== + dependencies: + "@jest/types" "^29.6.3" + "@sinonjs/fake-timers" "^10.0.2" + "@types/node" "*" + jest-message-util "^29.7.0" + jest-mock "^29.7.0" + jest-util "^29.7.0" + +"@jest/globals@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-29.7.0.tgz#8d9290f9ec47ff772607fa864ca1d5a2efae1d4d" + integrity sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/expect" "^29.7.0" + "@jest/types" "^29.6.3" + jest-mock "^29.7.0" + +"@jest/reporters@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-29.7.0.tgz#04b262ecb3b8faa83b0b3d321623972393e8f4c7" + integrity sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg== + dependencies: + "@bcoe/v8-coverage" "^0.2.3" + "@jest/console" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@jridgewell/trace-mapping" "^0.3.18" + "@types/node" "*" + chalk "^4.0.0" + collect-v8-coverage "^1.0.0" + exit "^0.1.2" + glob "^7.1.3" + graceful-fs "^4.2.9" + istanbul-lib-coverage "^3.0.0" + istanbul-lib-instrument "^6.0.0" + istanbul-lib-report "^3.0.0" + istanbul-lib-source-maps "^4.0.0" + istanbul-reports "^3.1.3" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + jest-worker "^29.7.0" + slash "^3.0.0" + string-length "^4.0.1" + strip-ansi "^6.0.0" + v8-to-istanbul "^9.0.1" + +"@jest/schemas@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.3.tgz#430b5ce8a4e0044a7e3819663305a7b3091c8e03" + integrity sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA== + dependencies: + "@sinclair/typebox" "^0.27.8" + +"@jest/source-map@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-29.6.3.tgz#d90ba772095cf37a34a5eb9413f1b562a08554c4" + integrity sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw== + dependencies: + "@jridgewell/trace-mapping" "^0.3.18" + callsites "^3.0.0" + graceful-fs "^4.2.9" + +"@jest/test-result@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-29.7.0.tgz#8db9a80aa1a097bb2262572686734baed9b1657c" + integrity sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA== + dependencies: + "@jest/console" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/istanbul-lib-coverage" "^2.0.0" + collect-v8-coverage "^1.0.0" + +"@jest/test-sequencer@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz#6cef977ce1d39834a3aea887a1726628a6f072ce" + integrity sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw== + dependencies: + "@jest/test-result" "^29.7.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + slash "^3.0.0" + +"@jest/transform@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-29.7.0.tgz#df2dd9c346c7d7768b8a06639994640c642e284c" + integrity sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw== + dependencies: + "@babel/core" "^7.11.6" + "@jest/types" "^29.6.3" + "@jridgewell/trace-mapping" "^0.3.18" + babel-plugin-istanbul "^6.1.1" + chalk "^4.0.0" + convert-source-map "^2.0.0" + fast-json-stable-stringify "^2.1.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + jest-regex-util "^29.6.3" + jest-util "^29.7.0" + micromatch "^4.0.4" + pirates "^4.0.4" + slash "^3.0.0" + write-file-atomic "^4.0.2" + +"@jest/types@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.6.3.tgz#1131f8cf634e7e84c5e77bab12f052af585fba59" + integrity sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw== + dependencies: + "@jest/schemas" "^29.6.3" + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^17.0.8" + chalk "^4.0.0" + +"@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz#7e02e6eb5df901aaedb08514203b096614024098" + integrity sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ== + dependencies: + "@jridgewell/set-array" "^1.0.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/resolve-uri@^3.1.0": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721" + integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA== + +"@jridgewell/set-array@^1.0.1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" + integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== + +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": + version "1.4.15" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" + integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== + +"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.9": + version "0.3.20" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz#72e45707cf240fa6b081d0366f8265b0cd10197f" + integrity sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + 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": + 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== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.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" + integrity sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA== + dependencies: + type-detect "4.0.8" + +"@sinonjs/fake-timers@^10.0.2": + version "10.3.0" + resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz#55fdff1ecab9f354019129daf4df0dd4d923ea66" + integrity sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA== + dependencies: + "@sinonjs/commons" "^3.0.0" + +"@swc/core-darwin-arm64@1.4.16": + version "1.4.16" + resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.4.16.tgz#2cd45d709ce76d448d96bf8d0006849541436611" + integrity sha512-UOCcH1GvjRnnM/LWT6VCGpIk0OhHRq6v1U6QXuPt5wVsgXnXQwnf5k3sG5Cm56hQHDvhRPY6HCsHi/p0oek8oQ== + +"@swc/core-darwin-x64@1.4.16": + version "1.4.16" + resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.4.16.tgz#a5bc7d8b1dd850adb0bb95c6b5c742b92201fd01" + integrity sha512-t3bgqFoYLWvyVtVL6KkFNCINEoOrIlyggT/kJRgi1y0aXSr0oVgcrQ4ezJpdeahZZ4N+Q6vT3ffM30yIunELNA== + +"@swc/core-linux-arm-gnueabihf@1.4.16": + version "1.4.16" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.4.16.tgz#961744908ee5cbb79bc009dcf58cc8b831111f38" + integrity sha512-DvHuwvEF86YvSd0lwnzVcjOTZ0jcxewIbsN0vc/0fqm9qBdMMjr9ox6VCam1n3yYeRtj4VFgrjeNFksqbUejdQ== + +"@swc/core-linux-arm64-gnu@1.4.16": + version "1.4.16" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.4.16.tgz#43713be3f26757d82d2745dc25f8b63400e0a3d0" + integrity sha512-9Uu5YlPbyCvbidjKtYEsPpyZlu16roOZ5c2tP1vHfnU9bgf5Tz5q5VovSduNxPHx+ed2iC1b1URODHvDzbbDuQ== + +"@swc/core-linux-arm64-musl@1.4.16": + version "1.4.16" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.4.16.tgz#394a7d030f3a61902bd3947bb9d70d26d42f3c81" + integrity sha512-/YZq/qB1CHpeoL0eMzyqK5/tYZn/rzKoCYDviFU4uduSUIJsDJQuQA/skdqUzqbheOXKAd4mnJ1hT04RbJ8FPQ== + +"@swc/core-linux-x64-gnu@1.4.16": + version "1.4.16" + resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.4.16.tgz#71eb108b784f9d551ee8a35ebcdaed972f567981" + integrity sha512-UUjaW5VTngZYDcA8yQlrFmqs1tLi1TxbKlnaJwoNhel9zRQ0yG1YEVGrzTvv4YApSuIiDK18t+Ip927bwucuVQ== + +"@swc/core-linux-x64-musl@1.4.16": + version "1.4.16" + resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.4.16.tgz#10dbaedb4e3dfc7268e3a9a66ad3431471ef035b" + integrity sha512-aFhxPifevDTwEDKPi4eRYWzC0p/WYJeiFkkpNU5Uc7a7M5iMWPAbPFUbHesdlb9Jfqs5c07oyz86u+/HySBNPQ== + +"@swc/core-win32-arm64-msvc@1.4.16": + version "1.4.16" + resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.4.16.tgz#80247adff6c245ff32b44d773c1a148858cd655f" + integrity sha512-bTD43MbhIHL2s5QgCwyleaGwl96Gk/scF2TaVKdUe4QlJCDV/YK9h5oIBAp63ckHtE8GHlH4c8dZNBiAXn4Org== + +"@swc/core-win32-ia32-msvc@1.4.16": + version "1.4.16" + resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.4.16.tgz#e540afc3ccf3224267b4ddfb408f9d9737984686" + integrity sha512-/lmZeAN/qV5XbK2SEvi8e2RkIg8FQNYiSA8y2/Zb4gTUMKVO5JMLH0BSWMiIKMstKDPDSxMWgwJaQHF8UMyPmQ== + +"@swc/core-win32-x64-msvc@1.4.16": + version "1.4.16" + resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.4.16.tgz#f880939fca32c181adfe7e3abd2b6b7857bd3489" + integrity sha512-BPAfFfODWXtUu6SwaTTftDHvcbDyWBSI/oanUeRbQR5vVWkXoQ3cxLTsDluc3H74IqXS5z1Uyoe0vNo2hB1opA== + +"@swc/core@^1.3.102": + version "1.4.16" + resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.4.16.tgz#d175bae2acfecd53bcbd4293f1fba5ec316634a0" + integrity sha512-Xaf+UBvW6JNuV131uvSNyMXHn+bh6LyKN4tbv7tOUFQpXyz/t9YWRE04emtlUW9Y0qrm/GKFCbY8n3z6BpZbTA== + dependencies: + "@swc/counter" "^0.1.2" + "@swc/types" "^0.1.5" + optionalDependencies: + "@swc/core-darwin-arm64" "1.4.16" + "@swc/core-darwin-x64" "1.4.16" + "@swc/core-linux-arm-gnueabihf" "1.4.16" + "@swc/core-linux-arm64-gnu" "1.4.16" + "@swc/core-linux-arm64-musl" "1.4.16" + "@swc/core-linux-x64-gnu" "1.4.16" + "@swc/core-linux-x64-musl" "1.4.16" + "@swc/core-win32-arm64-msvc" "1.4.16" + "@swc/core-win32-ia32-msvc" "1.4.16" + "@swc/core-win32-x64-msvc" "1.4.16" + +"@swc/counter@^0.1.2", "@swc/counter@^0.1.3": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@swc/counter/-/counter-0.1.3.tgz#cc7463bd02949611c6329596fccd2b0ec782b0e9" + integrity sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ== + +"@swc/jest@^0.2.29": + version "0.2.36" + resolved "https://registry.yarnpkg.com/@swc/jest/-/jest-0.2.36.tgz#2797450a30d28b471997a17e901ccad946fe693e" + integrity sha512-8X80dp81ugxs4a11z1ka43FPhP+/e+mJNXJSxiNYk8gIX/jPBtY4gQTrKu/KIoco8bzKuPI5lUxjfLiGsfvnlw== + dependencies: + "@jest/create-cache-key-function" "^29.7.0" + "@swc/counter" "^0.1.3" + jsonc-parser "^3.2.0" + +"@swc/types@^0.1.5": + version "0.1.6" + resolved "https://registry.yarnpkg.com/@swc/types/-/types-0.1.6.tgz#2f13f748995b247d146de2784d3eb7195410faba" + integrity sha512-/JLo/l2JsT/LRd80C3HfbmVpxOAJ11FO2RCEslFrgzLltoP9j8XIbsyDcfCt2WWyX+CM96rBoNM+IToAkFOugg== + dependencies: + "@swc/counter" "^0.1.3" + +"@tsconfig/node10@^1.0.7": + version "1.0.8" + resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.8.tgz#c1e4e80d6f964fbecb3359c43bd48b40f7cadad9" + integrity sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg== + +"@tsconfig/node12@^1.0.7": + version "1.0.9" + resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.9.tgz#62c1f6dee2ebd9aead80dc3afa56810e58e1a04c" + integrity sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw== + +"@tsconfig/node14@^1.0.0": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.1.tgz#95f2d167ffb9b8d2068b0b235302fafd4df711f2" + integrity sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg== + +"@tsconfig/node16@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.2.tgz#423c77877d0569db20e1fc80885ac4118314010e" + integrity sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA== + +"@types/babel__core@^7.1.14": + version "7.20.5" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.5.tgz#3df15f27ba85319caa07ba08d0721889bb39c017" + integrity sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA== + dependencies: + "@babel/parser" "^7.20.7" + "@babel/types" "^7.20.7" + "@types/babel__generator" "*" + "@types/babel__template" "*" + "@types/babel__traverse" "*" + +"@types/babel__generator@*": + version "7.6.8" + resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.8.tgz#f836c61f48b1346e7d2b0d93c6dacc5b9535d3ab" + integrity sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw== + dependencies: + "@babel/types" "^7.0.0" + +"@types/babel__template@*": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.4.tgz#5672513701c1b2199bc6dad636a9d7491586766f" + integrity sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + +"@types/babel__traverse@*", "@types/babel__traverse@^7.0.6": + version "7.20.4" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.20.4.tgz#ec2c06fed6549df8bc0eb4615b683749a4a92e1b" + integrity sha512-mSM/iKUk5fDDrEV/e83qY+Cr3I1+Q3qqTuEn++HAWYjEa1+NxZr6CNrcJGf2ZTnq4HoFGC3zaTPZTobCzCFukA== + 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" + integrity sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ== + dependencies: + "@types/node" "*" + +"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": + version "2.0.6" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz#7739c232a1fee9b4d3ce8985f314c0c6d33549d7" + integrity sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w== + +"@types/istanbul-lib-report@*": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz#53047614ae72e19fc0401d872de3ae2b4ce350bf" + integrity sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA== + dependencies: + "@types/istanbul-lib-coverage" "*" + +"@types/istanbul-reports@^3.0.0": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz#0f03e3d2f670fbdac586e34b433783070cc16f54" + integrity sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ== + dependencies: + "@types/istanbul-lib-report" "*" + +"@types/jest@^29.4.0": + version "29.5.11" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.11.tgz#0c13aa0da7d0929f078ab080ae5d4ced80fa2f2c" + integrity sha512-S2mHmYIVe13vrm6q4kN6fLYYAka15ALQki/vgDC3mIukEOx8WJlv0kQPM+d4w8Gp6u0uSdKND04IlTXBv0rwnQ== + dependencies: + expect "^29.0.0" + pretty-format "^29.0.0" + +"@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@*": + version "20.10.5" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.10.5.tgz#47ad460b514096b7ed63a1dae26fad0914ed3ab2" + integrity sha512-nNPsNE65wjMxEKI93yOP+NPGGBJz/PoN3kZsVLee0XMiJolxSekEVD8wRwBUBqkwc7UWop0edW50yrCQW4CyRw== + dependencies: + undici-types "~5.26.4" + +"@types/node@^20.17.6": + version "20.17.6" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.17.6.tgz#6e4073230c180d3579e8c60141f99efdf5df0081" + integrity sha512-VEI7OdvK2wP7XHnsuXbAJnEpEkF6NjSN45QJlL4VGqZSXsnicpesdTWsg9RISeSdYd3yeRj/y3k5KGjUXYnFwQ== + dependencies: + undici-types "~6.19.2" + +"@types/stack-utils@^2.0.0": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.3.tgz#6209321eb2c1712a7e7466422b8cb1fc0d9dd5d8" + integrity sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw== + +"@types/yargs-parser@*": + version "21.0.3" + resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.3.tgz#815e30b786d2e8f0dcd85fd5bcf5e1a04d008f15" + integrity sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ== + +"@types/yargs@^17.0.8": + version "17.0.32" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.32.tgz#030774723a2f7faafebf645f4e5a48371dca6229" + integrity sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog== + dependencies: + "@types/yargs-parser" "*" + +"@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.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.3.1" + natural-compare "^1.4.0" + ts-api-utils "^2.0.1" + +"@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" "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@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" "8.31.1" + "@typescript-eslint/visitor-keys" "8.31.1" + +"@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" "8.31.1" + "@typescript-eslint/utils" "8.31.1" + debug "^4.3.4" + ts-api-utils "^2.0.1" + +"@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@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" "8.31.1" + "@typescript-eslint/visitor-keys" "8.31.1" + debug "^4.3.4" + fast-glob "^3.3.2" + is-glob "^4.0.3" + minimatch "^9.0.4" + semver "^7.6.0" + ts-api-utils "^2.0.1" + +"@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" + "@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": + 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" "8.31.1" + eslint-visitor-keys "^4.2.0" + +acorn-jsx@^5.3.2: + version "5.3.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +acorn-walk@^8.1.1: + version "8.2.0" + 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== + +aggregate-error@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" + integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== + dependencies: + clean-stack "^2.0.0" + indent-string "^4.0.0" + +ajv@^6.12.4: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ansi-escapes@^4.2.1: + version "4.3.2" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + 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" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +ansi-styles@^5.0.0: + version "5.2.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" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +arg@^4.1.0: + version "4.1.3" + resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" + integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +babel-jest@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.7.0.tgz#f4369919225b684c56085998ac63dbd05be020d5" + integrity sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg== + dependencies: + "@jest/transform" "^29.7.0" + "@types/babel__core" "^7.1.14" + babel-plugin-istanbul "^6.1.1" + babel-preset-jest "^29.6.3" + chalk "^4.0.0" + graceful-fs "^4.2.9" + slash "^3.0.0" + +babel-plugin-istanbul@^6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz#fa88ec59232fd9b4e36dbbc540a8ec9a9b47da73" + integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@istanbuljs/load-nyc-config" "^1.0.0" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-instrument "^5.0.4" + test-exclude "^6.0.0" + +babel-plugin-jest-hoist@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz#aadbe943464182a8922c3c927c3067ff40d24626" + integrity sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg== + dependencies: + "@babel/template" "^7.3.3" + "@babel/types" "^7.3.3" + "@types/babel__core" "^7.1.14" + "@types/babel__traverse" "^7.0.6" + +babel-preset-current-node-syntax@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz#b4399239b89b2a011f9ddbe3e4f401fc40cff73b" + integrity sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ== + 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-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.8.3" + "@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-preset-jest@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz#fa05fa510e7d493896d7b0dd2033601c840f171c" + integrity sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA== + dependencies: + babel-plugin-jest-hoist "^29.6.3" + babel-preset-current-node-syntax "^1.0.0" + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + +braces@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== + dependencies: + fill-range "^7.1.1" + +browserslist@^4.22.2: + version "4.22.2" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.22.2.tgz#704c4943072bd81ea18997f3bd2180e89c77874b" + integrity sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A== + dependencies: + caniuse-lite "^1.0.30001565" + electron-to-chromium "^1.4.601" + node-releases "^2.0.14" + update-browserslist-db "^1.0.13" + +bs-logger@0.x: + version "0.2.6" + resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" + integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog== + dependencies: + fast-json-stable-stringify "2.x" + +bser@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" + integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== + dependencies: + node-int64 "^0.4.0" + +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +camelcase@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +camelcase@^6.2.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + +caniuse-lite@^1.0.30001565: + version "1.0.30001570" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001570.tgz#b4e5c1fa786f733ab78fc70f592df6b3f23244ca" + integrity sha512-+3e0ASu4sw1SWaoCtvPeyXp+5PsjigkSt8OXZbF9StH5pQWbxEjLAZE3n8Aup5udop1uRiKA7a4utUk/uoSpUw== + +chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.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== + dependencies: + 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" + integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== + +ci-info@^3.2.0: + version "3.9.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" + integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== + +cjs-module-lexer@^1.0.0: + version "1.2.3" + 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" + integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.1" + wrap-ansi "^7.0.0" + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ== + +collect-v8-coverage@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz#c0b29bcd33bcd0779a1344c2136051e6afd3d9e9" + integrity sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q== + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +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" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +convert-source-map@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" + integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== + +create-jest@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/create-jest/-/create-jest-29.7.0.tgz#a355c5b3cb1e1af02ba177fe7afd7feee49a5320" + integrity sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q== + dependencies: + "@jest/types" "^29.6.3" + chalk "^4.0.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + jest-config "^29.7.0" + jest-util "^29.7.0" + prompts "^2.0.1" + +create-require@^1.1.0: + version "1.1.1" + 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.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== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +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== + dependencies: + ms "^2.1.3" + +dedent@^1.0.0: + version "1.5.1" + resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.5.1.tgz#4f3fc94c8b711e9bb2800d185cd6ad20f2a90aff" + integrity sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg== + +deep-is@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== + +deepmerge@^4.2.2: + version "4.3.1" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" + integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== + +detect-newline@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" + integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== + +diff-sequences@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.6.3.tgz#4deaf894d11407c51efc8418012f9e70b84ea921" + integrity sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q== + +diff@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" + integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== + +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" + integrity sha512-X4ze/9Sc3QWs6h92yerwqv7aB/uU8vCjZcrMjA8N9R1pjMFRe44dLsck5FzLilOYvcXuDn93B+bpGYyufc70gQ== + +emittery@^0.13.1: + version "0.13.1" + resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.13.1.tgz#c04b8c3457490e0847ae51fced3af52d338e3dad" + integrity sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ== + +emoji-regex@^8.0.0: + version "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" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + +escape-string-regexp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" + integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== + +escape-string-regexp@^4.0.0: + version "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.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.9.1" + +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@^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: + 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-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.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" + "@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.6" + debug "^4.3.2" + escape-string-regexp "^4.0.0" + 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 "^8.0.0" + find-up "^5.0.0" + glob-parent "^6.0.2" + ignore "^5.2.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + json-stable-stringify-without-jsonify "^1.0.1" + lodash.merge "^4.6.2" + minimatch "^3.1.2" + natural-compare "^1.4.0" + optionator "^0.9.3" + +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.14.0" + acorn-jsx "^5.3.2" + 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.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" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^5.1.0, estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +execa@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== + 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" + +exit@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + integrity sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ== + +expect@^29.0.0, expect@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/expect/-/expect-29.7.0.tgz#578874590dcb3214514084c08115d8aee61e11bc" + integrity sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw== + dependencies: + "@jest/expect-utils" "^29.7.0" + jest-get-type "^29.6.3" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-diff@^1.1.2: + version "1.3.0" + resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.3.0.tgz#ece407fa550a64d638536cd727e129c61616e0f0" + integrity sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw== + +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== + 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-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== + +fastq@^1.6.0: + version "1.17.1" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.17.1.tgz#2a523f07a4e7b1e81a42b91b8bf2254107753b47" + integrity sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w== + dependencies: + reusify "^1.0.4" + +fb-watchman@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.2.tgz#e9524ee6b5c77e9e5001af0f85f3adbb8623255c" + integrity sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA== + dependencies: + bser "2.1.1" + +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 "^4.0.0" + +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== + dependencies: + to-regex-range "^5.0.1" + +find-up@^4.0.0, find-up@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +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: + flatted "^3.2.9" + keyv "^4.5.4" + +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" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +fsevents@^2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-package-type@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" + integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== + +get-stdin@^8.0.0: + version "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: + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + +glob-parent@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob-parent@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + +glob@^7.1.3, glob@^7.1.4: + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + 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@^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" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + +graphemer@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" + integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +hasown@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.0.tgz#f4c513d454a57b7c7e1650778de226b11700546c" + integrity sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA== + 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" + integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== + +human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== + +iconv-lite@^0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" + integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== + dependencies: + safer-buffer ">= 2.1.2 < 3.0.0" + +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== + +import-fresh@^3.2.1: + version "3.3.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +import-local@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.1.0.tgz#b4479df8a5fd44f6cdce24070675676063c95cb4" + integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg== + dependencies: + pkg-dir "^4.2.0" + resolve-cwd "^3.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== + +indent-string@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" + integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@^2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== + +is-core-module@^2.13.0: + version "2.13.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384" + integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw== + dependencies: + hasown "^2.0.0" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-generator-fn@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" + integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== + +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +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-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== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz#2d166c4b0644d43a39f04bf6c2edd1e585f31756" + integrity sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg== + +istanbul-lib-instrument@^5.0.4: + version "5.2.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz#d10c8885c2125574e1c231cacadf955675e1ce3d" + integrity sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg== + dependencies: + "@babel/core" "^7.12.3" + "@babel/parser" "^7.14.7" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.2.0" + semver "^6.3.0" + +istanbul-lib-instrument@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.1.tgz#71e87707e8041428732518c6fb5211761753fbdf" + integrity sha512-EAMEJBsYuyyztxMxW3g7ugGPkrZsV57v0Hmv3mm1uQsmB+QnZuepg731CRaIgeUVSdmsTngOkSnauNF8p7FIhA== + dependencies: + "@babel/core" "^7.12.3" + "@babel/parser" "^7.14.7" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.2.0" + semver "^7.5.4" + +istanbul-lib-report@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz#908305bac9a5bd175ac6a74489eafd0fc2445a7d" + integrity sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw== + dependencies: + istanbul-lib-coverage "^3.0.0" + make-dir "^4.0.0" + supports-color "^7.1.0" + +istanbul-lib-source-maps@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz#895f3a709fcfba34c6de5a42939022f3e4358551" + integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw== + dependencies: + debug "^4.1.1" + istanbul-lib-coverage "^3.0.0" + source-map "^0.6.1" + +istanbul-reports@^3.1.3: + version "3.1.6" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.6.tgz#2544bcab4768154281a2f0870471902704ccaa1a" + integrity sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg== + dependencies: + html-escaper "^2.0.0" + istanbul-lib-report "^3.0.0" + +jest-changed-files@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-29.7.0.tgz#1c06d07e77c78e1585d020424dedc10d6e17ac3a" + integrity sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w== + dependencies: + execa "^5.0.0" + jest-util "^29.7.0" + p-limit "^3.1.0" + +jest-circus@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-29.7.0.tgz#b6817a45fcc835d8b16d5962d0c026473ee3668a" + integrity sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/expect" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + dedent "^1.0.0" + is-generator-fn "^2.0.0" + jest-each "^29.7.0" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-runtime "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" + p-limit "^3.1.0" + pretty-format "^29.7.0" + pure-rand "^6.0.0" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-cli@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-29.7.0.tgz#5592c940798e0cae677eec169264f2d839a37995" + integrity sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg== + dependencies: + "@jest/core" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" + chalk "^4.0.0" + create-jest "^29.7.0" + exit "^0.1.2" + import-local "^3.0.2" + jest-config "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" + yargs "^17.3.1" + +jest-config@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-29.7.0.tgz#bcbda8806dbcc01b1e316a46bb74085a84b0245f" + integrity sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ== + dependencies: + "@babel/core" "^7.11.6" + "@jest/test-sequencer" "^29.7.0" + "@jest/types" "^29.6.3" + babel-jest "^29.7.0" + chalk "^4.0.0" + ci-info "^3.2.0" + deepmerge "^4.2.2" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-circus "^29.7.0" + jest-environment-node "^29.7.0" + jest-get-type "^29.6.3" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-runner "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" + micromatch "^4.0.4" + parse-json "^5.2.0" + pretty-format "^29.7.0" + slash "^3.0.0" + strip-json-comments "^3.1.1" + +jest-diff@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.7.0.tgz#017934a66ebb7ecf6f205e84699be10afd70458a" + integrity sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw== + dependencies: + chalk "^4.0.0" + diff-sequences "^29.6.3" + jest-get-type "^29.6.3" + pretty-format "^29.7.0" + +jest-docblock@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-29.7.0.tgz#8fddb6adc3cdc955c93e2a87f61cfd350d5d119a" + integrity sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g== + dependencies: + detect-newline "^3.0.0" + +jest-each@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-29.7.0.tgz#162a9b3f2328bdd991beaabffbb74745e56577d1" + integrity sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ== + dependencies: + "@jest/types" "^29.6.3" + chalk "^4.0.0" + jest-get-type "^29.6.3" + jest-util "^29.7.0" + pretty-format "^29.7.0" + +jest-environment-node@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-29.7.0.tgz#0b93e111dda8ec120bc8300e6d1fb9576e164376" + integrity sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/fake-timers" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + jest-mock "^29.7.0" + jest-util "^29.7.0" + +jest-get-type@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.6.3.tgz#36f499fdcea197c1045a127319c0481723908fd1" + integrity sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw== + +jest-haste-map@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-29.7.0.tgz#3c2396524482f5a0506376e6c858c3bbcc17b104" + integrity sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA== + dependencies: + "@jest/types" "^29.6.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 "^29.6.3" + jest-util "^29.7.0" + jest-worker "^29.7.0" + micromatch "^4.0.4" + walker "^1.0.8" + optionalDependencies: + fsevents "^2.3.2" + +jest-leak-detector@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz#5b7ec0dadfdfec0ca383dc9aa016d36b5ea4c728" + integrity sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw== + dependencies: + jest-get-type "^29.6.3" + pretty-format "^29.7.0" + +jest-matcher-utils@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz#ae8fec79ff249fd592ce80e3ee474e83a6c44f12" + integrity sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g== + dependencies: + chalk "^4.0.0" + jest-diff "^29.7.0" + jest-get-type "^29.6.3" + pretty-format "^29.7.0" + +jest-message-util@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.7.0.tgz#8bc392e204e95dfe7564abbe72a404e28e51f7f3" + integrity sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w== + dependencies: + "@babel/code-frame" "^7.12.13" + "@jest/types" "^29.6.3" + "@types/stack-utils" "^2.0.0" + chalk "^4.0.0" + graceful-fs "^4.2.9" + micromatch "^4.0.4" + pretty-format "^29.7.0" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-mock@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-29.7.0.tgz#4e836cf60e99c6fcfabe9f99d017f3fdd50a6347" + integrity sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw== + dependencies: + "@jest/types" "^29.6.3" + "@types/node" "*" + jest-util "^29.7.0" + +jest-pnp-resolver@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz#930b1546164d4ad5937d5540e711d4d38d4cad2e" + integrity sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w== + +jest-regex-util@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-29.6.3.tgz#4a556d9c776af68e1c5f48194f4d0327d24e8a52" + integrity sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg== + +jest-resolve-dependencies@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz#1b04f2c095f37fc776ff40803dc92921b1e88428" + integrity sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA== + dependencies: + jest-regex-util "^29.6.3" + jest-snapshot "^29.7.0" + +jest-resolve@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-29.7.0.tgz#64d6a8992dd26f635ab0c01e5eef4399c6bcbc30" + integrity sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA== + dependencies: + chalk "^4.0.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + jest-pnp-resolver "^1.2.2" + jest-util "^29.7.0" + jest-validate "^29.7.0" + resolve "^1.20.0" + resolve.exports "^2.0.0" + slash "^3.0.0" + +jest-runner@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-29.7.0.tgz#809af072d408a53dcfd2e849a4c976d3132f718e" + integrity sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ== + dependencies: + "@jest/console" "^29.7.0" + "@jest/environment" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + emittery "^0.13.1" + graceful-fs "^4.2.9" + jest-docblock "^29.7.0" + jest-environment-node "^29.7.0" + jest-haste-map "^29.7.0" + jest-leak-detector "^29.7.0" + jest-message-util "^29.7.0" + jest-resolve "^29.7.0" + jest-runtime "^29.7.0" + jest-util "^29.7.0" + jest-watcher "^29.7.0" + jest-worker "^29.7.0" + p-limit "^3.1.0" + source-map-support "0.5.13" + +jest-runtime@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-29.7.0.tgz#efecb3141cf7d3767a3a0cc8f7c9990587d3d817" + integrity sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/fake-timers" "^29.7.0" + "@jest/globals" "^29.7.0" + "@jest/source-map" "^29.6.3" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + cjs-module-lexer "^1.0.0" + collect-v8-coverage "^1.0.0" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + jest-message-util "^29.7.0" + jest-mock "^29.7.0" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" + slash "^3.0.0" + strip-bom "^4.0.0" + +jest-snapshot@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-29.7.0.tgz#c2c574c3f51865da1bb329036778a69bf88a6be5" + integrity sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw== + dependencies: + "@babel/core" "^7.11.6" + "@babel/generator" "^7.7.2" + "@babel/plugin-syntax-jsx" "^7.7.2" + "@babel/plugin-syntax-typescript" "^7.7.2" + "@babel/types" "^7.3.3" + "@jest/expect-utils" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + babel-preset-current-node-syntax "^1.0.0" + chalk "^4.0.0" + expect "^29.7.0" + graceful-fs "^4.2.9" + jest-diff "^29.7.0" + jest-get-type "^29.6.3" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + natural-compare "^1.4.0" + pretty-format "^29.7.0" + semver "^7.5.3" + +jest-util@^29.0.0, jest-util@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.7.0.tgz#23c2b62bfb22be82b44de98055802ff3710fc0bc" + integrity sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA== + dependencies: + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + ci-info "^3.2.0" + graceful-fs "^4.2.9" + picomatch "^2.2.3" + +jest-validate@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-29.7.0.tgz#7bf705511c64da591d46b15fce41400d52147d9c" + integrity sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw== + dependencies: + "@jest/types" "^29.6.3" + camelcase "^6.2.0" + chalk "^4.0.0" + jest-get-type "^29.6.3" + leven "^3.1.0" + pretty-format "^29.7.0" + +jest-watcher@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-29.7.0.tgz#7810d30d619c3a62093223ce6bb359ca1b28a2f2" + integrity sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g== + dependencies: + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + emittery "^0.13.1" + jest-util "^29.7.0" + string-length "^4.0.1" + +jest-worker@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-29.7.0.tgz#acad073acbbaeb7262bd5389e1bcf43e10058d4a" + integrity sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw== + dependencies: + "@types/node" "*" + jest-util "^29.7.0" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +jest@^29.4.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest/-/jest-29.7.0.tgz#994676fc24177f088f1c5e3737f5697204ff2613" + integrity sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw== + dependencies: + "@jest/core" "^29.7.0" + "@jest/types" "^29.6.3" + import-local "^3.0.2" + jest-cli "^29.7.0" + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^3.13.1: + version "3.14.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" + integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +jsesc@^2.5.1: + version "2.5.2" + 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" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== + +json5@^2.2.2, json5@^2.2.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" + integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== + +jsonc-parser@^3.2.0: + version "3.2.1" + 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" + integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== + +leven@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" + integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== + +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + +lines-and-columns@^1.1.6: + version "1.2.4" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" + integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + +lodash.memoize@4.x: + version "4.1.2" + resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" + integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag== + +lodash.merge@^4.6.2: + version "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" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + +make-dir@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-4.0.0.tgz#c3c2307a771277cd9638305f915c29ae741b614e" + integrity sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw== + dependencies: + semver "^7.5.3" + +make-error@1.x, make-error@^1.1.1: + version "1.3.6" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" + integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== + +makeerror@1.0.12: + version "1.0.12" + resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a" + integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg== + 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: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +micromatch@^4.0.4: + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== + dependencies: + braces "^3.0.3" + picomatch "^2.3.1" + +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== + +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.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-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: + "@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" + resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== + +node-releases@^2.0.14: + version "2.0.14" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b" + integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw== + +normalize-path@^3.0.0: + version "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" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.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" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +onetime@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + +optionator@^0.9.3: + version "0.9.3" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.3.tgz#007397d44ed1872fdc6ed31360190f81814e2c64" + integrity sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg== + dependencies: + "@aashutoshrathi/word-wrap" "^1.2.3" + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + +p-all@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-all/-/p-all-3.0.0.tgz#077c023c37e75e760193badab2bad3ccd5782bfb" + integrity sha512-qUZbvbBFVXm6uJ7U/WDiO0fv6waBMbjlCm4E66oZdRR+egswICarIdHyVSZZHudH8T5SF8x/JG0q0duFzPnlBw== + dependencies: + p-map "^4.0.0" + +p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-limit@^3.0.2, p-limit@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + +p-map@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" + integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== + dependencies: + aggregate-error "^3.0.0" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parse-json@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" + integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== + 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" + +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" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-key@^3.0.0, path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +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== + +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" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +pirates@^4.0.4: + version "4.0.6" + resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.6.tgz#3018ae32ecfcff6c29ba2267cbf21166ac1f36b9" + integrity sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg== + +pkg-dir@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + +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" + integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== + dependencies: + fast-diff "^1.1.2" + +prettier@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.1.1.tgz#6ba9f23165d690b6cbdaa88cb0807278f7019848" + integrity sha512-22UbSzg8luF4UuZtzgiUOfcGM8s4tjBv6dJRT7j275NXsy2jb4aJa4NNveul5x4eqlF1wuhuR2RElK71RvmVaw== + +pretty-format@^29.0.0, pretty-format@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.7.0.tgz#ca42c758310f365bfa71a0bda0a807160b776812" + integrity sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ== + dependencies: + "@jest/schemas" "^29.6.3" + ansi-styles "^5.0.0" + react-is "^18.0.0" + +prompts@^2.0.1: + version "2.4.2" + resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" + integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== + dependencies: + 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" + integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== + +pure-rand@^6.0.0: + version "6.0.4" + resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-6.0.4.tgz#50b737f6a925468679bff00ad20eade53f37d5c7" + integrity sha512-LA0Y9kxMYv47GIPJy6MI84fqTd2HmYZI83W/kM/SkKfDlajnZYfmXFTxkbY+xSBPkLJxltMa9hIkmdc29eguMA== + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +react-is@^18.0.0: + version "18.2.0" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" + integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== + +readable-stream@^3.4.0: + version "3.6.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + +resolve-cwd@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" + integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== + dependencies: + resolve-from "^5.0.0" + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + +resolve.exports@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-2.0.2.tgz#f8c934b8e6a13f539e38b7098e2e36134f01e800" + integrity sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg== + +resolve@^1.20.0: + version "1.22.8" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" + integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== + dependencies: + is-core-module "^2.13.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + 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" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +"safer-buffer@>= 2.1.2 < 3.0.0": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +semver@^6.3.0, semver@^6.3.1: + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + +semver@^7.5.3: + version "7.5.4" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" + integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== + dependencies: + lru-cache "^6.0.0" + +semver@^7.5.4: + version "7.6.3" + 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" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +signal-exit@^3.0.3, signal-exit@^3.0.7: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + +sisteransi@^1.0.5: + version "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" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +source-map-support@0.5.13: + version "0.5.13" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932" + integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@^0.6.0, source-map@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== + +stack-utils@^2.0.3: + version "2.0.6" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.6.tgz#aaf0748169c02fc33c8232abccf933f54a1cc34f" + integrity sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ== + dependencies: + escape-string-regexp "^2.0.0" + +string-length@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" + integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ== + dependencies: + char-regex "^1.0.2" + strip-ansi "^6.0.0" + +string-to-stream@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/string-to-stream/-/string-to-stream-3.0.1.tgz#480e6fb4d5476d31cb2221f75307a5dcb6638a42" + integrity sha512-Hl092MV3USJuUCC6mfl9sPzGloA3K5VwdIeJjYIkXY/8K+mUvaeEabWJgArp+xXrsWxCajeT2pc4axbVhIZJyg== + dependencies: + readable-stream "^3.4.0" + +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== + +strip-bom@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" + integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== + +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + +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.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" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.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== + dependencies: + has-flag "^4.0.0" + +supports-color@^8.0.0: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + 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.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/core" "^0.1.0" + tslib "^2.6.2" + +test-exclude@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" + integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== + dependencies: + "@istanbuljs/schema" "^0.1.2" + glob "^7.1.4" + minimatch "^3.0.4" + +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" + +"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" + resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" + integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +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" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-29.1.1.tgz#f58fe62c63caf7bfcc5cc6472082f79180f0815b" + integrity sha512-D6xjnnbP17cC85nliwGiL+tpoKN0StpgE0TeOjXQTU6MVCfsB4v7aW05CgQ/1OywGb0x/oy9hHFnN+sczTiRaA== + dependencies: + bs-logger "0.x" + fast-json-stable-stringify "2.x" + jest-util "^29.0.0" + json5 "^2.2.3" + lodash.memoize "4.x" + make-error "1.x" + semver "^7.5.3" + yargs-parser "^21.0.1" + +ts-node@^10.5.0: + version "10.7.0" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.7.0.tgz#35d503d0fab3e2baa672a0e94f4b40653c2463f5" + integrity sha512-TbIGS4xgJoX2i3do417KSaep1uRAW/Lu+WAL2doDHC0D6ummjirVOXU5/7aiZotbQ5p1Zp9tP7U6cYhA0O7M8A== + dependencies: + "@cspotcode/source-map-support" "0.7.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.0" + yn "3.1.1" + +"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.7" + fast-glob "^3.3.2" + get-stdin "^8.0.0" + p-all "^3.0.0" + picocolors "^1.1.1" + signal-exit "^3.0.7" + string-to-stream "^3.0.1" + superstruct "^1.0.4" + tslib "^2.8.1" + yargs "^17.7.2" + +tsconfig-paths@^4.0.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz#ef78e19039133446d244beac0fd6a1632e2d107c" + integrity sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg== + dependencies: + json5 "^2.2.2" + minimist "^1.2.6" + strip-bom "^3.0.0" + +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" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + +type-detect@4.0.8: + version "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.21.3: + version "0.21.3" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== + +typescript-eslint@8.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== + +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" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz#3c5e4f5c083661bd38ef64b6328c26ed6c8248c4" + integrity sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg== + dependencies: + escalade "^3.1.1" + picocolors "^1.0.0" + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +util-deprecate@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + +v8-compile-cache-lib@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.0.tgz#0582bcb1c74f3a2ee46487ceecf372e46bce53e8" + integrity sha512-mpSYqfsFvASnSn5qMiwrr4VKfumbPyONLCOPmsR3A6pTY/r0+tSaVbgPWSAIuzbk3lCTa+FForeTiO+wBQGkjA== + +v8-to-istanbul@^9.0.1: + version "9.2.0" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz#2ed7644a245cddd83d4e087b9b33b3e62dfd10ad" + integrity sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA== + dependencies: + "@jridgewell/trace-mapping" "^0.3.12" + "@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" + integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== + dependencies: + makeerror "1.0.12" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +write-file-atomic@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-4.0.2.tgz#a9df01ae5b77858a027fd2e80768ee433555fcfd" + integrity sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg== + dependencies: + imurmurhash "^0.1.4" + signal-exit "^3.0.7" + +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + +yallist@^4.0.0: + version "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@^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== + 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" + +yn@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" + integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== From e42483da0feb32bbbebccd0c01cac87cdebce7a2 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 21 May 2025 11:54:51 +0000 Subject: [PATCH 02/91] feat(api): update via SDK Studio --- .stats.yml | 2 +- api.md | 1 + src/client.ts | 2 + src/resources/image-operations.ts | 103 +++++++----------------------- src/resources/index.ts | 1 + 5 files changed, 28 insertions(+), 81 deletions(-) diff --git a/.stats.yml b/.stats.yml index efeed00..d6a2dab 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 17 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/scan-documents%2Fscan-documents-04f736d0a9ae5151fec360201288ee49dc02cc4f60adf1ff17c5e3a0bbb639b4.yml openapi_spec_hash: e9d1be2b0eae296e605a9a79af48ab63 -config_hash: 51f73a6963f0ae992703d2d999576437 +config_hash: d5cdbd7a76734de48c644766d9ccf85d diff --git a/api.md b/api.md index ea8198c..884d588 100644 --- a/api.md +++ b/api.md @@ -48,6 +48,7 @@ Types: - ExtractTextRequest - ExtractTextResponse - ImageFromTaskResponse +- JsonSchemaSpec - WarpRequest - WarpResponse diff --git a/src/client.ts b/src/client.ts index 4d65f4b..b47256b 100644 --- a/src/client.ts +++ b/src/client.ts @@ -38,6 +38,7 @@ import { ImageOperationExtractTextParams, ImageOperationWarpParams, ImageOperations, + JsonSchemaSpec, WarpRequest, WarpResponse, } from './resources/image-operations'; @@ -770,6 +771,7 @@ export declare namespace ScanDocuments { type ExtractTextRequest as ExtractTextRequest, type ExtractTextResponse as ExtractTextResponse, type ImageFromTaskResponse as ImageFromTaskResponse, + type JsonSchemaSpec as JsonSchemaSpec, type WarpRequest as WarpRequest, type WarpResponse as WarpResponse, type ImageOperationApplyEffectParams as ImageOperationApplyEffectParams, diff --git a/src/resources/image-operations.ts b/src/resources/image-operations.ts index b9a1acc..fab8729 100644 --- a/src/resources/image-operations.ts +++ b/src/resources/image-operations.ts @@ -819,9 +819,9 @@ export namespace ExtractTextRequest { format?: string; - items?: Schema.Items; + items?: ImageOperationsAPI.JsonSchemaSpec; - properties?: Record; + properties?: Record; required?: Array; @@ -829,44 +829,6 @@ export namespace ExtractTextRequest { [k: string]: unknown; } - - export namespace Schema { - export interface Items { - description?: string; - - example?: unknown; - - format?: string; - - items?: unknown; - - properties?: Record; - - required?: Array; - - type?: 'string' | 'number' | 'integer' | 'boolean' | 'array' | 'object'; - - [k: string]: unknown; - } - - export interface Properties { - description?: string; - - example?: unknown; - - format?: string; - - items?: unknown; - - properties?: Record; - - required?: Array; - - type?: 'string' | 'number' | 'integer' | 'boolean' | 'array' | 'object'; - - [k: string]: unknown; - } - } } } @@ -1084,6 +1046,24 @@ export namespace ImageFromTaskResponse { } } +export interface JsonSchemaSpec { + description?: string; + + example?: unknown; + + format?: string; + + items?: JsonSchemaSpec; + + properties?: Record; + + required?: Array; + + type?: 'string' | 'number' | 'integer' | 'boolean' | 'array' | 'object'; + + [k: string]: unknown; +} + /** * Transform an image by warping it to a quadrilateral. */ @@ -1430,9 +1410,9 @@ export declare namespace ImageOperationExtractTextParams { format?: string; - items?: Schema.Items; + items?: ImageOperationsAPI.JsonSchemaSpec; - properties?: Record; + properties?: Record; required?: Array; @@ -1440,44 +1420,6 @@ export declare namespace ImageOperationExtractTextParams { [k: string]: unknown; } - - export namespace Schema { - export interface Items { - description?: string; - - example?: unknown; - - format?: string; - - items?: unknown; - - properties?: Record; - - required?: Array; - - type?: 'string' | 'number' | 'integer' | 'boolean' | 'array' | 'object'; - - [k: string]: unknown; - } - - export interface Properties { - description?: string; - - example?: unknown; - - format?: string; - - items?: unknown; - - properties?: Record; - - required?: Array; - - type?: 'string' | 'number' | 'integer' | 'boolean' | 'array' | 'object'; - - [k: string]: unknown; - } - } } } @@ -1509,6 +1451,7 @@ export declare namespace ImageOperations { type ExtractTextRequest as ExtractTextRequest, type ExtractTextResponse as ExtractTextResponse, type ImageFromTaskResponse as ImageFromTaskResponse, + type JsonSchemaSpec as JsonSchemaSpec, type WarpRequest as WarpRequest, type WarpResponse as WarpResponse, type ImageOperationApplyEffectParams as ImageOperationApplyEffectParams, diff --git a/src/resources/index.ts b/src/resources/index.ts index fd22245..2d6e2ff 100644 --- a/src/resources/index.ts +++ b/src/resources/index.ts @@ -13,6 +13,7 @@ export { type ExtractTextRequest, type ExtractTextResponse, type ImageFromTaskResponse, + type JsonSchemaSpec, type WarpRequest, type WarpResponse, type ImageOperationApplyEffectParams, From ddfed840440c19d3556efa60a44de5b927dc342e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 21 May 2025 12:05:08 +0000 Subject: [PATCH 03/91] chore: update SDK settings --- .github/workflows/release-doctor.yml | 20 +++++++++ .release-please-manifest.json | 3 ++ .stats.yml | 2 +- CONTRIBUTING.md | 6 +-- README.md | 4 +- bin/check-release-environment | 18 ++++++++ package.json | 2 +- release-please-config.json | 64 ++++++++++++++++++++++++++++ src/version.ts | 2 +- 9 files changed, 113 insertions(+), 8 deletions(-) create mode 100644 .github/workflows/release-doctor.yml create mode 100644 .release-please-manifest.json create mode 100644 bin/check-release-environment create mode 100644 release-please-config.json diff --git a/.github/workflows/release-doctor.yml b/.github/workflows/release-doctor.yml new file mode 100644 index 0000000..3635a99 --- /dev/null +++ b/.github/workflows/release-doctor.yml @@ -0,0 +1,20 @@ +name: Release Doctor +on: + pull_request: + branches: + - main + workflow_dispatch: + +jobs: + release_doctor: + name: release doctor + runs-on: ubuntu-latest + if: github.repository == 'Scan-Documents/node-sdk' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch' || startsWith(github.head_ref, 'release-please') || github.head_ref == 'next') + + steps: + - uses: actions/checkout@v4 + + - name: Check release environment + run: | + bash ./bin/check-release-environment + env: diff --git a/.release-please-manifest.json b/.release-please-manifest.json new file mode 100644 index 0000000..67dcd73 --- /dev/null +++ b/.release-please-manifest.json @@ -0,0 +1,3 @@ +{ + ".": "0.0.1-alpha.0" +} diff --git a/.stats.yml b/.stats.yml index d6a2dab..3304975 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 17 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/scan-documents%2Fscan-documents-04f736d0a9ae5151fec360201288ee49dc02cc4f60adf1ff17c5e3a0bbb639b4.yml openapi_spec_hash: e9d1be2b0eae296e605a9a79af48ab63 -config_hash: d5cdbd7a76734de48c644766d9ccf85d +config_hash: 4f4827d325f696522fa77bbcdce72cef diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ef88a64..af042e6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -42,15 +42,15 @@ If you’d like to use the repository from source, you can either install from g To install via git: ```sh -$ npm install git+ssh://git@github.com:stainless-sdks/scan-documents-typescript.git +$ npm install git+ssh://git@github.com:Scan-Documents/node-sdk.git ``` Alternatively, to link a local copy of the repo: ```sh # Clone -$ git clone https://www.github.com/stainless-sdks/scan-documents-typescript -$ cd scan-documents-typescript +$ git clone https://www.github.com/Scan-Documents/node-sdk +$ cd node-sdk # With yarn $ yarn link diff --git a/README.md b/README.md index 8ca2846..55cd92b 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ It is generated with [Stainless](https://www.stainless.com/). ## Installation ```sh -npm install git+ssh://git@github.com:stainless-sdks/scan-documents-typescript.git +npm install git+ssh://git@github.com:Scan-Documents/node-sdk.git ``` > [!NOTE] @@ -385,7 +385,7 @@ This package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) con We take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience. -We are keen for your feedback; please open an [issue](https://www.github.com/stainless-sdks/scan-documents-typescript/issues) with questions, bugs, or suggestions. +We are keen for your feedback; please open an [issue](https://www.github.com/Scan-Documents/node-sdk/issues) with questions, bugs, or suggestions. ## Requirements diff --git a/bin/check-release-environment b/bin/check-release-environment new file mode 100644 index 0000000..6b43775 --- /dev/null +++ b/bin/check-release-environment @@ -0,0 +1,18 @@ +#!/usr/bin/env bash + +errors=() + +lenErrors=${#errors[@]} + +if [[ lenErrors -gt 0 ]]; then + echo -e "Found the following errors in the release environment:\n" + + for error in "${errors[@]}"; do + echo -e "- $error\n" + done + + exit 1 +fi + +echo "The environment is ready to push releases!" + diff --git a/package.json b/package.json index 2e5b442..822037a 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "types": "dist/index.d.ts", "main": "dist/index.js", "type": "commonjs", - "repository": "github:stainless-sdks/scan-documents-typescript", + "repository": "github:Scan-Documents/node-sdk", "license": "Apache-2.0", "packageManager": "yarn@1.22.22", "files": [ diff --git a/release-please-config.json b/release-please-config.json new file mode 100644 index 0000000..1ebd0bd --- /dev/null +++ b/release-please-config.json @@ -0,0 +1,64 @@ +{ + "packages": { + ".": {} + }, + "$schema": "https://raw.githubusercontent.com/stainless-api/release-please/main/schemas/config.json", + "include-v-in-tag": true, + "include-component-in-tag": false, + "versioning": "prerelease", + "prerelease": true, + "bump-minor-pre-major": true, + "bump-patch-for-minor-pre-major": false, + "pull-request-header": "Automated Release PR", + "pull-request-title-pattern": "release: ${version}", + "changelog-sections": [ + { + "type": "feat", + "section": "Features" + }, + { + "type": "fix", + "section": "Bug Fixes" + }, + { + "type": "perf", + "section": "Performance Improvements" + }, + { + "type": "revert", + "section": "Reverts" + }, + { + "type": "chore", + "section": "Chores" + }, + { + "type": "docs", + "section": "Documentation" + }, + { + "type": "style", + "section": "Styles" + }, + { + "type": "refactor", + "section": "Refactors" + }, + { + "type": "test", + "section": "Tests", + "hidden": true + }, + { + "type": "build", + "section": "Build System" + }, + { + "type": "ci", + "section": "Continuous Integration", + "hidden": true + } + ], + "release-type": "node", + "extra-files": ["src/version.ts", "README.md"] +} diff --git a/src/version.ts b/src/version.ts index 55a1a52..db692bc 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1 +1 @@ -export const VERSION = '0.0.1-alpha.0'; +export const VERSION = '0.0.1-alpha.0'; // x-release-please-version From 9b54dafeb6d79fac7d48fb7c5d4e0ea27e14d0df Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 21 May 2025 12:07:25 +0000 Subject: [PATCH 04/91] chore: update SDK settings --- .github/workflows/publish-npm.yml | 32 ++++++++++++++++++++++++++++ .github/workflows/release-doctor.yml | 1 + .stats.yml | 2 +- CONTRIBUTING.md | 14 ++++++++++++ README.md | 5 +---- bin/check-release-environment | 4 ++++ 6 files changed, 53 insertions(+), 5 deletions(-) create mode 100644 .github/workflows/publish-npm.yml diff --git a/.github/workflows/publish-npm.yml b/.github/workflows/publish-npm.yml new file mode 100644 index 0000000..87ccb3f --- /dev/null +++ b/.github/workflows/publish-npm.yml @@ -0,0 +1,32 @@ +# This workflow is triggered when a GitHub release is created. +# It can also be run manually to re-publish to NPM in case it failed for some reason. +# You can run this workflow by navigating to https://www.github.com/Scan-Documents/node-sdk/actions/workflows/publish-npm.yml +name: Publish NPM +on: + workflow_dispatch: + + release: + types: [published] + +jobs: + publish: + name: publish + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Set up Node + uses: actions/setup-node@v3 + with: + node-version: '20' + + - name: Install dependencies + run: | + yarn install + + - name: Publish to NPM + run: | + bash ./bin/publish-npm + env: + NPM_TOKEN: ${{ secrets.SCAN_DOCUMENTS_NPM_TOKEN || secrets.NPM_TOKEN }} diff --git a/.github/workflows/release-doctor.yml b/.github/workflows/release-doctor.yml index 3635a99..3537409 100644 --- a/.github/workflows/release-doctor.yml +++ b/.github/workflows/release-doctor.yml @@ -18,3 +18,4 @@ jobs: run: | bash ./bin/check-release-environment env: + NPM_TOKEN: ${{ secrets.SCAN_DOCUMENTS_NPM_TOKEN || secrets.NPM_TOKEN }} diff --git a/.stats.yml b/.stats.yml index 3304975..c351faf 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 17 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/scan-documents%2Fscan-documents-04f736d0a9ae5151fec360201288ee49dc02cc4f60adf1ff17c5e3a0bbb639b4.yml openapi_spec_hash: e9d1be2b0eae296e605a9a79af48ab63 -config_hash: 4f4827d325f696522fa77bbcdce72cef +config_hash: 277743e0fb95d030cf82282dc09bf31a diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index af042e6..a5f44c4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -91,3 +91,17 @@ To format and fix all lint issues automatically: ```sh $ yarn fix ``` + +## Publishing and releases + +Changes made to this repository via the automated release PR pipeline should publish to npm automatically. If +the changes aren't made through the automated pipeline, you may want to make releases manually. + +### Publish with a GitHub workflow + +You can release to package managers by using [the `Publish NPM` GitHub action](https://www.github.com/Scan-Documents/node-sdk/actions/workflows/publish-npm.yml). This requires a setup organization or repository secret to be set up. + +### Publish manually + +If you need to manually release a package, you can run the `bin/publish-npm` script with an `NPM_TOKEN` set on +the environment. diff --git a/README.md b/README.md index 55cd92b..9703cec 100644 --- a/README.md +++ b/README.md @@ -11,12 +11,9 @@ It is generated with [Stainless](https://www.stainless.com/). ## Installation ```sh -npm install git+ssh://git@github.com:Scan-Documents/node-sdk.git +npm install scan-documents ``` -> [!NOTE] -> Once this package is [published to npm](https://app.stainless.com/docs/guides/publish), this will become: `npm install scan-documents` - ## Usage The full API of this library can be found in [api.md](api.md). diff --git a/bin/check-release-environment b/bin/check-release-environment index 6b43775..d3cfc3d 100644 --- a/bin/check-release-environment +++ b/bin/check-release-environment @@ -2,6 +2,10 @@ errors=() +if [ -z "${NPM_TOKEN}" ]; then + errors+=("The SCAN_DOCUMENTS_NPM_TOKEN secret has not been set. Please set it in either this repository's secrets or your organization secrets") +fi + lenErrors=${#errors[@]} if [[ lenErrors -gt 0 ]]; then From 0fbf0d8893f1673aa5a8d009d1855717c8635133 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 21 May 2025 12:10:31 +0000 Subject: [PATCH 05/91] chore(internal): version bump --- .release-please-manifest.json | 2 +- package.json | 2 +- src/version.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 67dcd73..d7a8735 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.0.1-alpha.0" + ".": "0.1.0-alpha.1" } diff --git a/package.json b/package.json index 822037a..b8bbc7b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "scan-documents", - "version": "0.0.1-alpha.0", + "version": "0.1.0-alpha.1", "description": "The official TypeScript library for the Scan Documents API", "author": "Scan Documents <>", "types": "dist/index.d.ts", diff --git a/src/version.ts b/src/version.ts index db692bc..b0bfd9e 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1 +1 @@ -export const VERSION = '0.0.1-alpha.0'; // x-release-please-version +export const VERSION = '0.1.0-alpha.1'; // x-release-please-version From 955ee64b0c45bcb89529aa97792aa5859e266cb8 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 21 May 2025 12:26:58 +0000 Subject: [PATCH 06/91] chore: configure new SDK language --- .github/workflows/ci.yml | 5 +- .github/workflows/publish-npm.yml | 11 +- .prettierignore | 2 +- .stats.yml | 2 +- eslint.config.mjs | 2 +- packages/mcp-server/README.md | 198 + packages/mcp-server/build | 36 + packages/mcp-server/jest.config.ts | 17 + packages/mcp-server/package.json | 72 + .../scripts/postprocess-dist-package-json.cjs | 12 + packages/mcp-server/src/compat.ts | 429 ++ packages/mcp-server/src/dynamic-tools.ts | 152 + packages/mcp-server/src/index.ts | 102 + packages/mcp-server/src/options.ts | 361 ++ packages/mcp-server/src/server.ts | 128 + packages/mcp-server/src/tools.ts | 1 + .../src/tools/events/list-events.ts | 34 + .../src/tools/files/delete-files.ts | 31 + .../src/tools/files/download-files.ts | 31 + .../mcp-server/src/tools/files/list-files.ts | 36 + .../src/tools/files/retrieve-files.ts | 31 + .../src/tools/files/upload-files.ts | 36 + .../apply-effect-image-operations.ts | 41 + .../convert-image-operations.ts | 90 + .../detect-documents-image-operations.ts | 32 + .../extract-text-image-operations.ts | 150 + .../image-operations/warp-image-operations.ts | 44 + packages/mcp-server/src/tools/index.ts | 118 + .../extract-pages-pdf-operations.ts | 40 + .../pdf-operations/merge-pdf-operations.ts | 40 + .../pdf-operations/render-pdf-operations.ts | 44 + .../pdf-operations/split-pdf-operations.ts | 36 + .../mcp-server/src/tools/tasks/list-tasks.ts | 34 + .../src/tools/tasks/retrieve-tasks.ts | 32 + packages/mcp-server/tests/compat.test.ts | 1068 +++++ .../mcp-server/tests/dynamic-tools.test.ts | 172 + packages/mcp-server/tests/options.test.ts | 193 + packages/mcp-server/tests/tools.test.ts | 225 ++ packages/mcp-server/tsc-multi.json | 7 + packages/mcp-server/tsconfig.build.json | 18 + packages/mcp-server/tsconfig.dist-src.json | 11 + packages/mcp-server/tsconfig.json | 37 + packages/mcp-server/yarn.lock | 3514 +++++++++++++++++ release-please-config.json | 11 +- scripts/build | 6 + scripts/build-all | 5 + scripts/publish-packages.ts | 102 + scripts/utils/make-dist-package-json.cjs | 8 + 48 files changed, 7801 insertions(+), 6 deletions(-) create mode 100644 packages/mcp-server/README.md create mode 100644 packages/mcp-server/build create mode 100644 packages/mcp-server/jest.config.ts create mode 100644 packages/mcp-server/package.json create mode 100644 packages/mcp-server/scripts/postprocess-dist-package-json.cjs create mode 100644 packages/mcp-server/src/compat.ts create mode 100644 packages/mcp-server/src/dynamic-tools.ts create mode 100644 packages/mcp-server/src/index.ts create mode 100644 packages/mcp-server/src/options.ts create mode 100644 packages/mcp-server/src/server.ts create mode 100644 packages/mcp-server/src/tools.ts create mode 100644 packages/mcp-server/src/tools/events/list-events.ts create mode 100644 packages/mcp-server/src/tools/files/delete-files.ts create mode 100644 packages/mcp-server/src/tools/files/download-files.ts create mode 100644 packages/mcp-server/src/tools/files/list-files.ts create mode 100644 packages/mcp-server/src/tools/files/retrieve-files.ts create mode 100644 packages/mcp-server/src/tools/files/upload-files.ts create mode 100644 packages/mcp-server/src/tools/image-operations/apply-effect-image-operations.ts create mode 100644 packages/mcp-server/src/tools/image-operations/convert-image-operations.ts create mode 100644 packages/mcp-server/src/tools/image-operations/detect-documents-image-operations.ts create mode 100644 packages/mcp-server/src/tools/image-operations/extract-text-image-operations.ts create mode 100644 packages/mcp-server/src/tools/image-operations/warp-image-operations.ts create mode 100644 packages/mcp-server/src/tools/index.ts create mode 100644 packages/mcp-server/src/tools/pdf-operations/extract-pages-pdf-operations.ts create mode 100644 packages/mcp-server/src/tools/pdf-operations/merge-pdf-operations.ts create mode 100644 packages/mcp-server/src/tools/pdf-operations/render-pdf-operations.ts create mode 100644 packages/mcp-server/src/tools/pdf-operations/split-pdf-operations.ts create mode 100644 packages/mcp-server/src/tools/tasks/list-tasks.ts create mode 100644 packages/mcp-server/src/tools/tasks/retrieve-tasks.ts create mode 100644 packages/mcp-server/tests/compat.test.ts create mode 100644 packages/mcp-server/tests/dynamic-tools.test.ts create mode 100644 packages/mcp-server/tests/options.test.ts create mode 100644 packages/mcp-server/tests/tools.test.ts create mode 100644 packages/mcp-server/tsc-multi.json create mode 100644 packages/mcp-server/tsconfig.build.json create mode 100644 packages/mcp-server/tsconfig.dist-src.json create mode 100644 packages/mcp-server/tsconfig.json create mode 100644 packages/mcp-server/yarn.lock create mode 100755 scripts/build-all create mode 100644 scripts/publish-packages.ts diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a13c266..9b1b538 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -72,10 +72,13 @@ jobs: - name: Set up Node uses: actions/setup-node@v4 with: - node-version: '20' + node-version: '22' - name: Bootstrap run: ./scripts/bootstrap + - name: Build + run: ./scripts/build + - name: Run tests run: ./scripts/test diff --git a/.github/workflows/publish-npm.yml b/.github/workflows/publish-npm.yml index 87ccb3f..514981f 100644 --- a/.github/workflows/publish-npm.yml +++ b/.github/workflows/publish-npm.yml @@ -4,6 +4,10 @@ name: Publish NPM on: workflow_dispatch: + inputs: + path: + description: The path to run the release in, e.g. '.' or 'packages/mcp-server' + required: true release: types: [published] @@ -27,6 +31,11 @@ jobs: - name: Publish to NPM run: | - bash ./bin/publish-npm + if [ -n "${{ github.event.inputs.path }}" ]; then + PATHS_RELEASED='[\"${{ github.event.inputs.path }}\"]' + else + PATHS_RELEASED='[\".\", \"packages/mcp-server\"]' + fi + yarn tsn scripts/publish-packages.ts "{ \"paths_released\": \"$PATHS_RELEASED\" }" env: NPM_TOKEN: ${{ secrets.SCAN_DOCUMENTS_NPM_TOKEN || secrets.NPM_TOKEN }} diff --git a/.prettierignore b/.prettierignore index 3548c5a..7cc13dd 100644 --- a/.prettierignore +++ b/.prettierignore @@ -4,4 +4,4 @@ CHANGELOG.md /deno # don't format tsc output, will break source maps -/dist +dist diff --git a/.stats.yml b/.stats.yml index c351faf..2efa153 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 17 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/scan-documents%2Fscan-documents-04f736d0a9ae5151fec360201288ee49dc02cc4f60adf1ff17c5e3a0bbb639b4.yml openapi_spec_hash: e9d1be2b0eae296e605a9a79af48ab63 -config_hash: 277743e0fb95d030cf82282dc09bf31a +config_hash: 242faa43d2cdcb84a3ac26da983e34c6 diff --git a/eslint.config.mjs b/eslint.config.mjs index 699a035..a4591a8 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -34,7 +34,7 @@ export default tseslint.config( }, }, { - files: ['tests/**', 'examples/**'], + files: ['tests/**', 'examples/**', 'packages/**'], rules: { 'no-restricted-imports': 'off', }, diff --git a/packages/mcp-server/README.md b/packages/mcp-server/README.md new file mode 100644 index 0000000..f36e13c --- /dev/null +++ b/packages/mcp-server/README.md @@ -0,0 +1,198 @@ +# Scan Documents TypeScript MCP Server + +It is generated with [Stainless](https://www.stainless.com/). + +## Installation + +### Direct invocation + +You can run the MCP Server directly via `npx`: + +```sh +export SCAN_DOCUMENTS_API_KEY="My API Key" +npx -y scan-documents-mcp@latest +``` + +### Via MCP Client + +There is a partial list of existing clients at [modelcontextprotocol.io](https://modelcontextprotocol.io/clients). If you already +have a client, consult their documentation to install the MCP server. + +For clients with a configuration JSON, it might look something like this: + +```json +{ + "mcpServers": { + "scan_documents_api": { + "command": "npx", + "args": ["-y", "scan-documents-mcp", "--client=claude", "--tools=all"], + "env": { + "SCAN_DOCUMENTS_API_KEY": "My API Key" + } + } + } +} +``` + +## Exposing endpoints to your MCP Client + +There are two ways to expose endpoints as tools in the MCP server: + +1. Exposing one tool per endpoint, and filtering as necessary +2. Exposing a set of tools to dynamically discover and invoke endpoints from the API + +### Filtering endpoints and tools + +You can run the package on the command line to discover and filter the set of tools that are exposed by the +MCP Server. This can be helpful for large APIs where including all endpoints at once is too much for your AI's +context window. + +You can filter by multiple aspects: + +- `--tool` includes a specific tool by name +- `--resource` includes all tools under a specific resource, and can have wildcards, e.g. `my.resource*` +- `--operation` includes just read (get/list) or just write operations + +### Dynamic tools + +If you specify `--tools=dynamic` to the MCP server, instead of exposing one tool per endpoint in the API, it will +expose the following tools: + +1. `list_api_endpoints` - Discovers available endpoints, with optional filtering by search query +2. `get_api_endpoint_schema` - Gets detailed schema information for a specific endpoint +3. `invoke_api_endpoint` - Executes any endpoint with the appropriate parameters + +This allows you to have the full set of API endpoints available to your MCP Client, while not requiring that all +of their schemas be loaded into context at once. Instead, the LLM will automatically use these tools together to +search for, look up, and invoke endpoints dynamically. However, due to the indirect nature of the schemas, it +can struggle to provide the correct properties a bit more than when tools are imported explicitly. Therefore, +you can opt-in to explicit tools, the dynamic tools, or both. + +See more information with `--help`. + +All of these command-line options can be repeated, combined together, and have corresponding exclusion versions (e.g. `--no-tool`). + +Use `--list` to see the list of available tools, or see below. + +### Specifying the MCP Client + +Different clients have varying abilities to handle arbitrary tools and schemas. + +You can specify the client you are using with the `--client` argument, and the MCP server will automatically +serve tools and schemas that are more compatible with that client. + +- `--client=`: Set all capabilities based on a known MCP client + + - Valid values: `openai-agents`, `claude`, `claude-code`, `cursor` + - Example: `--client=cursor` + +Additionally, if you have a client not on the above list, or the client has gotten better +over time, you can manually enable or disable certain capabilities: + +- `--capability=`: Specify individual client capabilities + - Available capabilities: + - `top-level-unions`: Enable support for top-level unions in tool schemas + - `valid-json`: Enable JSON string parsing for arguments + - `refs`: Enable support for $ref pointers in schemas + - `unions`: Enable support for union types (anyOf) in schemas + - `formats`: Enable support for format validations in schemas (e.g. date-time, email) + - `tool-name-length=N`: Set maximum tool name length to N characters + - Example: `--capability=top-level-unions --capability=tool-name-length=40` + - Example: `--capability=top-level-unions,tool-name-length=40` + +### Examples + +1. Filter for read operations on cards: + +```bash +--resource=cards --operation=read +``` + +2. Exclude specific tools while including others: + +```bash +--resource=cards --no-tool=create_cards +``` + +3. Configure for Cursor client with custom max tool name length: + +```bash +--client=cursor --capability=tool-name-length=40 +``` + +4. Complex filtering with multiple criteria: + +```bash +--resource=cards,accounts --operation=read --tag=kyc --no-tool=create_cards +``` + +## Importing the tools and server individually + +```js +// Import the server, generated endpoints, or the init function +import { server, endpoints, init } from "scan-documents-mcp/server"; + +// import a specific tool +import retrieveFiles from "scan-documents-mcp/tools/files/retrieve-files"; + +// initialize the server and all endpoints +init({ server, endpoints }); + +// manually start server +const transport = new StdioServerTransport(); +await server.connect(transport); + +// or initialize your own server with specific tools +const myServer = new McpServer(...); + +// define your own endpoint +const myCustomEndpoint = { + tool: { + name: 'my_custom_tool', + description: 'My custom tool', + inputSchema: zodToJsonSchema(z.object({ a_property: z.string() })), + }, + handler: async (client: client, args: any) => { + return { myResponse: 'Hello world!' }; + }) +}; + +// initialize the server with your custom endpoints +init({ server: myServer, endpoints: [retrieveFiles, myCustomEndpoint] }); +``` + +## Available Tools + +The following tools are available in this MCP server. + +### Resource `files`: + +- `retrieve_files` (`read`): Retrieves the data for a specific file by its ID. +- `list_files` (`read`): Retrieves a paginated list of files belonging to the authenticated user. +- `delete_files` (`write`): Deletes a specific file by its ID. +- `download_files` (`read`): Downloads the content of a specific file by its ID. +- `upload_files` (`write`): Uploads a file to the user's storage. The file size is limited to 10MB. + +### Resource `tasks`: + +- `retrieve_tasks` (`read`): Retrieves the data for a specific task by its ID. +- `list_tasks` (`read`): Retrieves a paginated list of tasks belonging to the authenticated user. + +### Resource `events`: + +- `list_events` (`read`): Retrieves a paginated list of events belonging to the authenticated user. + +### Resource `image_operations`: + +- `apply_effect_image_operations` (`write`): Creates a task to apply a specified visual effect to an image. +- `convert_image_operations` (`write`): Creates a task to convert an image file to a different format. +- `detect_documents_image_operations` (`write`): Creates a task to detect document boundaries within an image. +- `extract_text_image_operations` (`write`): Creates a task to extract text from a specified image file. +- `warp_image_operations` (`write`): Creates a task to apply perspective correction (warp) to an image based on detected document boundaries. + +### Resource `pdf_operations`: + +- `extract_pages_pdf_operations` (`write`): Creates a task to extract specific pages from a PDF file into a new PDF file. +- `merge_pdf_operations` (`write`): Creates a task to merge multiple PDF and/or image files into a single PDF file. +- `render_pdf_operations` (`write`): Creates a task to render specified pages of a PDF file as images. +- `split_pdf_operations` (`write`): Creates a task to split a PDF file into multiple single-page PDF files. diff --git a/packages/mcp-server/build b/packages/mcp-server/build new file mode 100644 index 0000000..146ea13 --- /dev/null +++ b/packages/mcp-server/build @@ -0,0 +1,36 @@ +#!/usr/bin/env bash +set -exuo pipefail + +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 + +for file in LICENSE; do + if [ -e "../../${file}" ]; then cp "../../${file}" dist; fi +done + +for file in CHANGELOG.md; do + if [ -e "${file}" ]; then cp "${file}" dist; fi +done + +# this converts the export map paths for the dist directory +# and does a few other minor things +PKG_JSON_PATH=../../packages/mcp-server/package.json node ../../scripts/utils/make-dist-package-json.cjs > dist/package.json + +# updates the `scan-documents` dependency to point to NPM +node scripts/postprocess-dist-package-json.cjs + +# build to .js/.mjs/.d.ts files +npm exec tsc-multi + +cp tsconfig.dist-src.json dist/src/tsconfig.json + +# Add proper Node.js shebang to the top of the file +sed -i.bak '1s;^;#!/usr/bin/env node\n;' dist/index.js +rm dist/index.js.bak + +chmod +x dist/index.js + +DIST_PATH=./dist PKG_IMPORT_PATH=scan-documents-mcp/ node ../../scripts/utils/postprocess-files.cjs diff --git a/packages/mcp-server/jest.config.ts b/packages/mcp-server/jest.config.ts new file mode 100644 index 0000000..74d9910 --- /dev/null +++ b/packages/mcp-server/jest.config.ts @@ -0,0 +1,17 @@ +import type { JestConfigWithTsJest } from 'ts-jest'; + +const config: JestConfigWithTsJest = { + preset: 'ts-jest/presets/default-esm', + testEnvironment: 'node', + transform: { + '^.+\\.(t|j)sx?$': ['@swc/jest', { sourceMaps: 'inline' }], + }, + moduleNameMapper: { + '^scan-documents-mcp$': '/src/index.ts', + '^scan-documents-mcp/(.*)$': '/src/$1', + }, + modulePathIgnorePatterns: ['/dist/'], + testPathIgnorePatterns: ['scripts'], +}; + +export default config; diff --git a/packages/mcp-server/package.json b/packages/mcp-server/package.json new file mode 100644 index 0000000..4980744 --- /dev/null +++ b/packages/mcp-server/package.json @@ -0,0 +1,72 @@ +{ + "name": "scan-documents-mcp", + "version": "0.1.0-alpha.1", + "description": "The official MCP Server for the Scan Documents API", + "author": "Scan Documents <>", + "types": "dist/index.d.ts", + "main": "dist/index.js", + "type": "commonjs", + "repository": { + "type": "git", + "url": "git+https://github.com/Scan-Documents/node-sdk.git", + "directory": "packages/mcp-server" + }, + "homepage": "https://github.com/Scan-Documents/node-sdk/tree/main/packages/mcp-server#readme", + "license": "Apache-2.0", + "packageManager": "yarn@1.22.22", + "private": false, + "scripts": { + "test": "jest", + "build": "bash ./build", + "prepack": "echo 'to pack, run yarn build && (cd dist; yarn pack)' && exit 1", + "prepublishOnly": "echo 'to publish, run yarn build && (cd dist; yarn publish)' && exit 1", + "format": "prettier --write --cache --cache-strategy metadata . !dist", + "prepare": "npm run build", + "tsn": "ts-node -r tsconfig-paths/register", + "lint": "eslint --ext ts,js .", + "fix": "eslint --fix --ext ts,js ." + }, + "dependencies": { + "scan-documents": "file:../../dist/", + "@modelcontextprotocol/sdk": "^1.6.1", + "yargs": "^17.7.2", + "@cloudflare/cabidela": "^0.2.4", + "zod": "^3.24.4", + "zod-to-json-schema": "^3.24.5" + }, + "bin": { + "mcp-server": "dist/index.js" + }, + "devDependencies": { + "@types/jest": "^29.4.0", + "@typescript-eslint/eslint-plugin": "8.31.1", + "@typescript-eslint/parser": "8.31.1", + "eslint": "^8.49.0", + "eslint-plugin-prettier": "^5.0.1", + "eslint-plugin-unused-imports": "^3.0.0", + "jest": "^29.4.0", + "prettier": "^3.0.0", + "ts-jest": "^29.1.0", + "ts-morph": "^19.0.0", + "ts-node": "^10.5.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": "5.8.3" + }, + "imports": { + "scan-documents-mcp": ".", + "scan-documents-mcp/*": "./src/*" + }, + "exports": { + ".": { + "require": "./dist/index.js", + "default": "./dist/index.mjs" + }, + "./*.mjs": "./dist/*.mjs", + "./*.js": "./dist/*.js", + "./*": { + "require": "./dist/*.js", + "default": "./dist/*.mjs" + } + } +} diff --git a/packages/mcp-server/scripts/postprocess-dist-package-json.cjs b/packages/mcp-server/scripts/postprocess-dist-package-json.cjs new file mode 100644 index 0000000..c982e1c --- /dev/null +++ b/packages/mcp-server/scripts/postprocess-dist-package-json.cjs @@ -0,0 +1,12 @@ +const fs = require('fs'); +const pkgJson = require('../dist/package.json'); +const parentPkgJson = require('../../../package.json'); + +for (const dep in pkgJson.dependencies) { + // ensure we point to NPM instead of a local directory + if (dep === 'scan-documents') { + pkgJson.dependencies[dep] = '^' + parentPkgJson.version; + } +} + +fs.writeFileSync('dist/package.json', JSON.stringify(pkgJson, null, 2)); diff --git a/packages/mcp-server/src/compat.ts b/packages/mcp-server/src/compat.ts new file mode 100644 index 0000000..e4d48a4 --- /dev/null +++ b/packages/mcp-server/src/compat.ts @@ -0,0 +1,429 @@ +import { Tool } from '@modelcontextprotocol/sdk/types.js'; +import { Endpoint } from './tools'; + +export interface ClientCapabilities { + topLevelUnions: boolean; + validJson: boolean; + refs: boolean; + unions: boolean; + formats: boolean; + toolNameLength: number | undefined; +} + +export const defaultClientCapabilities: ClientCapabilities = { + topLevelUnions: true, + validJson: true, + refs: true, + unions: true, + formats: true, + toolNameLength: undefined, +}; + +/** + * Attempts to parse strings into JSON objects + */ +export function parseEmbeddedJSON(args: Record, schema: Record) { + let updated = false; + const newArgs: Record = Object.assign({}, args); + + for (const [key, value] of Object.entries(newArgs)) { + if (typeof value === 'string') { + try { + const parsed = JSON.parse(value); + newArgs[key] = parsed; + updated = true; + } catch (e) { + // Not valid JSON, leave as is + } + } + } + + if (updated) { + return newArgs; + } + + return args; +} + +export type JSONSchema = { + type?: string; + properties?: Record; + required?: string[]; + anyOf?: JSONSchema[]; + $ref?: string; + $defs?: Record; + [key: string]: any; +}; + +/** + * Truncates tool names to the specified length while ensuring uniqueness. + * If truncation would cause duplicate names, appends a number to make them unique. + */ +export function truncateToolNames(names: string[], maxLength: number): Map { + if (maxLength <= 0) { + return new Map(); + } + + const renameMap = new Map(); + const usedNames = new Set(); + + const toTruncate = names.filter((name) => name.length > maxLength); + + if (toTruncate.length === 0) { + return renameMap; + } + + const willCollide = + new Set(toTruncate.map((name) => name.slice(0, maxLength - 1))).size < toTruncate.length; + + if (!willCollide) { + for (const name of toTruncate) { + const truncatedName = name.slice(0, maxLength); + renameMap.set(name, truncatedName); + } + } else { + const baseLength = maxLength - 1; + + for (const name of toTruncate) { + const baseName = name.slice(0, baseLength); + let counter = 1; + + while (usedNames.has(baseName + counter)) { + counter++; + } + + const finalName = baseName + counter; + renameMap.set(name, finalName); + usedNames.add(finalName); + } + } + + return renameMap; +} + +/** + * Removes top-level unions from a tool by splitting it into multiple tools, + * one for each variant in the union. + */ +export function removeTopLevelUnions(tool: Tool): Tool[] { + const inputSchema = tool.inputSchema as JSONSchema; + const variants = inputSchema.anyOf; + + if (!variants || !Array.isArray(variants) || variants.length === 0) { + return [tool]; + } + + const defs = inputSchema.$defs || {}; + + return variants.map((variant, index) => { + const variantSchema: JSONSchema = { + ...inputSchema, + ...variant, + type: 'object', + properties: { + ...(inputSchema.properties || {}), + ...(variant.properties || {}), + }, + }; + + delete variantSchema.anyOf; + + if (!variantSchema['description']) { + variantSchema['description'] = tool.description; + } + + const usedDefs = findUsedDefs(variant, defs); + if (Object.keys(usedDefs).length > 0) { + variantSchema.$defs = usedDefs; + } else { + delete variantSchema.$defs; + } + + return { + ...tool, + name: `${tool.name}_${toSnakeCase(variant['title'] || `variant${index + 1}`)}`, + description: variant['description'] || tool.description, + inputSchema: variantSchema, + } as Tool; + }); +} + +function findUsedDefs(schema: JSONSchema, defs: Record): Record { + const usedDefs: Record = {}; + + if (typeof schema !== 'object' || schema === null) { + return usedDefs; + } + + if (schema.$ref) { + const refParts = schema.$ref.split('/'); + if (refParts[0] === '#' && refParts[1] === '$defs' && refParts[2]) { + const defName = refParts[2]; + const def = defs[defName]; + if (def) { + usedDefs[defName] = def; + Object.assign(usedDefs, findUsedDefs(def, defs)); + } + } + return usedDefs; + } + + for (const key in schema) { + if (key !== '$defs' && typeof schema[key] === 'object' && schema[key] !== null) { + Object.assign(usedDefs, findUsedDefs(schema[key] as JSONSchema, defs)); + } + } + + return usedDefs; +} + +/** + * Inlines all $refs in a schema, eliminating $defs. + * If a circular reference is detected, the circular property is removed. + */ +export function inlineRefs(schema: JSONSchema): JSONSchema { + if (!schema || typeof schema !== 'object') { + return schema; + } + + const clonedSchema = { ...schema }; + const defs: Record = schema.$defs || {}; + + delete clonedSchema.$defs; + + const result = inlineRefsRecursive(clonedSchema, defs, new Set()); + // The top level can never be null + return result === null ? {} : result; +} + +function inlineRefsRecursive( + schema: JSONSchema, + defs: Record, + refPath: Set, +): JSONSchema | null { + if (!schema || typeof schema !== 'object') { + return schema; + } + + if (Array.isArray(schema)) { + return schema.map((item) => { + const processed = inlineRefsRecursive(item, defs, refPath); + return processed === null ? {} : processed; + }) as JSONSchema; + } + + const result = { ...schema }; + + if ('$ref' in result && typeof result.$ref === 'string') { + if (result.$ref.startsWith('#/$defs/')) { + const refName = result.$ref.split('/').pop() as string; + const def = defs[refName]; + + // If we've already seen this ref in our path, we have a circular reference + if (refPath.has(result.$ref)) { + // For circular references, we completely remove the property + // by returning null. The parent will remove it. + return null; + } + + if (def) { + const newRefPath = new Set(refPath); + newRefPath.add(result.$ref); + + const inlinedDef = inlineRefsRecursive({ ...def }, defs, newRefPath); + + if (inlinedDef === null) { + return { ...result }; + } + + // Merge the inlined definition with the original schema's properties + // but preserve things like description, etc. + const { $ref, ...rest } = result; + return { ...inlinedDef, ...rest }; + } + } + + // Keep external refs as-is + return result; + } + + for (const key in result) { + if (result[key] && typeof result[key] === 'object') { + const processed = inlineRefsRecursive(result[key] as JSONSchema, defs, refPath); + if (processed === null) { + // Remove properties that would cause circular references + delete result[key]; + } else { + result[key] = processed; + } + } + } + + return result; +} + +/** + * Removes anyOf fields from a schema, using only the first variant. + */ +export function removeAnyOf(schema: JSONSchema): JSONSchema { + if (!schema || typeof schema !== 'object') { + return schema; + } + + if (Array.isArray(schema)) { + return schema.map((item) => removeAnyOf(item)) as JSONSchema; + } + + const result = { ...schema }; + + if ('anyOf' in result && Array.isArray(result.anyOf) && result.anyOf.length > 0) { + const firstVariant = result.anyOf[0]; + + if (firstVariant && typeof firstVariant === 'object') { + // Special handling for properties to ensure deep merge + if (firstVariant.properties && result.properties) { + result.properties = { + ...result.properties, + ...(firstVariant.properties as Record), + }; + } else if (firstVariant.properties) { + result.properties = { ...firstVariant.properties }; + } + + for (const key in firstVariant) { + if (key !== 'properties') { + result[key] = firstVariant[key]; + } + } + } + + delete result.anyOf; + } + + for (const key in result) { + if (result[key] && typeof result[key] === 'object') { + result[key] = removeAnyOf(result[key] as JSONSchema); + } + } + + return result; +} + +/** + * Removes format fields from a schema and appends them to the description. + */ +export function removeFormats(schema: JSONSchema, formatsCapability: boolean): JSONSchema { + if (formatsCapability) { + return schema; + } + + if (!schema || typeof schema !== 'object') { + return schema; + } + + if (Array.isArray(schema)) { + return schema.map((item) => removeFormats(item, formatsCapability)) as JSONSchema; + } + + const result = { ...schema }; + + if ('format' in result && typeof result['format'] === 'string') { + const formatStr = `(format: "${result['format']}")`; + + if ('description' in result && typeof result['description'] === 'string') { + result['description'] = `${result['description']} ${formatStr}`; + } else { + result['description'] = formatStr; + } + + delete result['format']; + } + + for (const key in result) { + if (result[key] && typeof result[key] === 'object') { + result[key] = removeFormats(result[key] as JSONSchema, formatsCapability); + } + } + + return result; +} + +/** + * Applies all compatibility transformations to the endpoints based on the provided capabilities. + */ +export function applyCompatibilityTransformations( + endpoints: Endpoint[], + capabilities: ClientCapabilities, +): Endpoint[] { + let transformedEndpoints = [...endpoints]; + + // Handle top-level unions first as this changes tool names + if (!capabilities.topLevelUnions) { + const newEndpoints: Endpoint[] = []; + + for (const endpoint of transformedEndpoints) { + const variantTools = removeTopLevelUnions(endpoint.tool); + + if (variantTools.length === 1) { + newEndpoints.push(endpoint); + } else { + for (const variantTool of variantTools) { + newEndpoints.push({ + ...endpoint, + tool: variantTool, + }); + } + } + } + + transformedEndpoints = newEndpoints; + } + + if (capabilities.toolNameLength) { + const toolNames = transformedEndpoints.map((endpoint) => endpoint.tool.name); + const renameMap = truncateToolNames(toolNames, capabilities.toolNameLength); + + transformedEndpoints = transformedEndpoints.map((endpoint) => ({ + ...endpoint, + tool: { + ...endpoint.tool, + name: renameMap.get(endpoint.tool.name) ?? endpoint.tool.name, + }, + })); + } + + if (!capabilities.refs || !capabilities.unions || !capabilities.formats) { + transformedEndpoints = transformedEndpoints.map((endpoint) => { + let schema = endpoint.tool.inputSchema as JSONSchema; + + if (!capabilities.refs) { + schema = inlineRefs(schema); + } + + if (!capabilities.unions) { + schema = removeAnyOf(schema); + } + + if (!capabilities.formats) { + schema = removeFormats(schema, capabilities.formats); + } + + return { + ...endpoint, + tool: { + ...endpoint.tool, + inputSchema: schema as typeof endpoint.tool.inputSchema, + }, + }; + }); + } + + return transformedEndpoints; +} + +function toSnakeCase(str: string): string { + return str + .replace(/\s+/g, '_') + .replace(/([a-z])([A-Z])/g, '$1_$2') + .toLowerCase(); +} diff --git a/packages/mcp-server/src/dynamic-tools.ts b/packages/mcp-server/src/dynamic-tools.ts new file mode 100644 index 0000000..b15efd3 --- /dev/null +++ b/packages/mcp-server/src/dynamic-tools.ts @@ -0,0 +1,152 @@ +import ScanDocuments from 'scan-documents'; +import { Endpoint } from './tools'; +import { zodToJsonSchema } from 'zod-to-json-schema'; +import { z } from 'zod'; +import { Cabidela } from '@cloudflare/cabidela'; + +function zodToInputSchema(schema: z.ZodSchema) { + return { + type: 'object' as const, + ...(zodToJsonSchema(schema) as any), + }; +} + +/** + * A list of tools that expose all the endpoints in the API dynamically. + * + * Instead of exposing every endpoint as it's own tool, which uses up too many tokens for LLMs to use at once, + * we expose a single tool that can be used to search for endpoints by name, resource, operation, or tag, and then + * a generic endpoint that can be used to invoke any endpoint with the provided arguments. + * + * @param endpoints - The endpoints to include in the list. + */ +export function dynamicTools(endpoints: Endpoint[]): Endpoint[] { + const listEndpointsSchema = z.object({ + search_query: z + .string() + .optional() + .describe( + 'An optional search query to filter the endpoints by. Provide a partial name, resource, operation, or tag to filter the endpoints returned.', + ), + }); + + const listEndpointsTool = { + metadata: { + resource: 'dynamic_tools', + operation: 'read' as const, + tags: [], + }, + tool: { + name: 'list_api_endpoints', + description: 'List or search for all endpoints in the Scan Documents TypeScript API', + inputSchema: zodToInputSchema(listEndpointsSchema), + }, + handler: async (client: ScanDocuments, args: Record | undefined) => { + const query = args && listEndpointsSchema.parse(args).search_query?.trim(); + + const filteredEndpoints = + query && query.length > 0 ? + endpoints.filter((endpoint) => { + const fieldsToMatch = [ + endpoint.tool.name, + endpoint.metadata.resource, + endpoint.metadata.operation, + ...endpoint.metadata.tags, + ]; + return fieldsToMatch.some((field) => field.toLowerCase().includes(query.toLowerCase())); + }) + : endpoints; + + return { + tools: filteredEndpoints.map(({ tool, metadata }) => ({ + name: tool.name, + description: tool.description, + resource: metadata.resource, + operation: metadata.operation, + tags: metadata.tags, + })), + }; + }, + }; + + const getEndpointSchema = z.object({ + endpoint: z.string().describe('The name of the endpoint to get the schema for.'), + }); + const getEndpointTool = { + metadata: { + resource: 'dynamic_tools', + operation: 'read' as const, + tags: [], + }, + tool: { + name: 'get_api_endpoint_schema', + description: + 'Get the schema for an endpoint in the Scan Documents TypeScript API. You can use the schema returned by this tool to invoke an endpoint with the `invoke_api_endpoint` tool.', + inputSchema: zodToInputSchema(getEndpointSchema), + }, + handler: async (client: ScanDocuments, args: Record | undefined) => { + if (!args) { + throw new Error('No endpoint provided'); + } + const endpointName = getEndpointSchema.parse(args).endpoint; + + const endpoint = endpoints.find((e) => e.tool.name === endpointName); + if (!endpoint) { + throw new Error(`Endpoint ${endpointName} not found`); + } + return endpoint.tool; + }, + }; + + const invokeEndpointSchema = z.object({ + endpoint_name: z.string().describe('The name of the endpoint to invoke.'), + args: z + .record(z.string(), z.any()) + .describe( + 'The arguments to pass to the endpoint. This must match the schema returned by the `get_api_endpoint_schema` tool.', + ), + }); + + const invokeEndpointTool = { + metadata: { + resource: 'dynamic_tools', + operation: 'write' as const, + tags: [], + }, + tool: { + name: 'invoke_api_endpoint', + description: + 'Invoke an endpoint in the Scan Documents TypeScript API. Note: use the `list_api_endpoints` tool to get the list of endpoints and `get_api_endpoint_schema` tool to get the schema for an endpoint.', + inputSchema: zodToInputSchema(invokeEndpointSchema), + }, + handler: async (client: ScanDocuments, args: Record | undefined) => { + if (!args) { + throw new Error('No endpoint provided'); + } + const { success, data, error } = invokeEndpointSchema.safeParse(args); + if (!success) { + throw new Error(`Invalid arguments for endpoint. ${error?.format()}`); + } + const { endpoint_name, args: endpointArgs } = data; + + const endpoint = endpoints.find((e) => e.tool.name === endpoint_name); + if (!endpoint) { + throw new Error( + `Endpoint ${endpoint_name} not found. Use the \`list_api_endpoints\` tool to get the list of available endpoints.`, + ); + } + + try { + // Try to validate the arguments for a better error message + const cabidela = new Cabidela(endpoint.tool.inputSchema, { fullErrors: true }); + cabidela.validate(endpointArgs); + } catch (error) { + throw new Error(`Invalid arguments for endpoint ${endpoint_name}:\n${error}`); + } + + return endpoint.handler(client, endpointArgs); + }, + }; + + return [getEndpointTool, listEndpointsTool, invokeEndpointTool]; +} diff --git a/packages/mcp-server/src/index.ts b/packages/mcp-server/src/index.ts new file mode 100644 index 0000000..17e31ce --- /dev/null +++ b/packages/mcp-server/src/index.ts @@ -0,0 +1,102 @@ +import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; +import { init, selectTools, server } from './server'; +import { Endpoint, endpoints } from './tools'; +import { ParsedOptions, parseOptions } from './options'; + +async function main() { + const options = parseOptionsOrError(); + + if (options.list) { + listAllTools(); + return; + } + + const includedTools = selectToolsOrError(endpoints, options); + + console.error( + `MCP Server starting with ${includedTools.length} tools:`, + includedTools.map((e) => e.tool.name), + ); + + init({ server, endpoints: includedTools }); + + const transport = new StdioServerTransport(); + await server.connect(transport); + console.error('MCP Server running on stdio'); +} + +if (require.main === module) { + main().catch((error) => { + console.error('Fatal error in main():', error); + process.exit(1); + }); +} + +function parseOptionsOrError() { + try { + return parseOptions(); + } catch (error) { + console.error('Error parsing options:', error); + process.exit(1); + } +} + +function selectToolsOrError(endpoints: Endpoint[], options: ParsedOptions) { + try { + const includedTools = selectTools(endpoints, options); + if (includedTools.length === 0) { + console.error('No tools match the provided filters.'); + process.exit(1); + } + return includedTools; + } catch (error) { + if (error instanceof Error) { + console.error('Error filtering tools:', error.message); + } else { + console.error('Error filtering tools:', error); + } + process.exit(1); + } +} + +function listAllTools() { + if (endpoints.length === 0) { + console.log('No tools available.'); + return; + } + console.log('Available tools:\n'); + + // Group endpoints by resource + const resourceGroups = new Map(); + + for (const endpoint of endpoints) { + const resource = endpoint.metadata.resource; + if (!resourceGroups.has(resource)) { + resourceGroups.set(resource, []); + } + resourceGroups.get(resource)!.push(endpoint); + } + + // Sort resources alphabetically + const sortedResources = Array.from(resourceGroups.keys()).sort(); + + // Display hierarchically by resource + for (const resource of sortedResources) { + console.log(`Resource: ${resource}`); + + const resourceEndpoints = resourceGroups.get(resource)!; + // Sort endpoints by tool name + resourceEndpoints.sort((a, b) => a.tool.name.localeCompare(b.tool.name)); + + for (const endpoint of resourceEndpoints) { + const { + tool, + metadata: { operation, tags }, + } = endpoint; + + console.log(` - ${tool.name} (${operation}) ${tags.length > 0 ? `tags: ${tags.join(', ')}` : ''}`); + console.log(` Description: ${tool.description}`); + } + console.log(''); + } +} diff --git a/packages/mcp-server/src/options.ts b/packages/mcp-server/src/options.ts new file mode 100644 index 0000000..4a2d166 --- /dev/null +++ b/packages/mcp-server/src/options.ts @@ -0,0 +1,361 @@ +import yargs from 'yargs'; +import { hideBin } from 'yargs/helpers'; +import { endpoints, Filter } from './tools'; +import { ClientCapabilities } from './compat'; + +type ClientType = 'openai-agents' | 'claude' | 'claude-code' | 'cursor'; + +// Client presets for compatibility +// Note that these could change over time as models get better, so this is +// a best effort. +const CLIENT_PRESETS: Record = { + 'openai-agents': { + topLevelUnions: false, + validJson: true, + refs: true, + unions: true, + formats: true, + toolNameLength: undefined, + }, + claude: { + topLevelUnions: true, + validJson: false, + refs: true, + unions: true, + formats: true, + toolNameLength: undefined, + }, + 'claude-code': { + topLevelUnions: false, + validJson: true, + refs: true, + unions: true, + formats: true, + toolNameLength: undefined, + }, + cursor: { + topLevelUnions: false, + validJson: true, + refs: false, + unions: false, + formats: false, + toolNameLength: 50, + }, +}; + +export interface ParsedOptions { + includeDynamicTools: boolean | undefined; + includeAllTools: boolean | undefined; + filters: Filter[]; + capabilities: ClientCapabilities; + list: boolean; +} + +const CAPABILITY_CHOICES = [ + 'top-level-unions', + 'valid-json', + 'refs', + 'unions', + 'formats', + 'tool-name-length', +] as const; + +type Capability = (typeof CAPABILITY_CHOICES)[number]; + +function parseCapabilityValue(cap: string): { name: Capability; value?: number } { + if (cap.startsWith('tool-name-length=')) { + const parts = cap.split('='); + if (parts.length === 2) { + const length = parseInt(parts[1]!, 10); + if (!isNaN(length)) { + return { name: 'tool-name-length', value: length }; + } + throw new Error(`Invalid tool-name-length value: ${parts[1]}. Expected a number.`); + } + throw new Error(`Invalid format for tool-name-length. Expected tool-name-length=N.`); + } + if (!CAPABILITY_CHOICES.includes(cap as Capability)) { + throw new Error(`Unknown capability: ${cap}. Valid capabilities are: ${CAPABILITY_CHOICES.join(', ')}`); + } + return { name: cap as Capability }; +} + +export function parseOptions(): ParsedOptions { + const opts = yargs(hideBin(process.argv)) + .option('tools', { + type: 'string', + array: true, + choices: ['dynamic', 'all'], + description: 'Use dynamic tools or all tools', + }) + .option('no-tools', { + type: 'string', + array: true, + choices: ['dynamic', 'all'], + description: 'Do not use any dynamic or all tools', + }) + .option('tool', { + type: 'string', + array: true, + description: 'Include tools matching the specified names', + }) + .option('resource', { + type: 'string', + array: true, + description: 'Include tools matching the specified resources', + }) + .option('operation', { + type: 'string', + array: true, + choices: ['read', 'write'], + description: 'Include tools matching the specified operations', + }) + .option('tag', { + type: 'string', + array: true, + description: 'Include tools with the specified tags', + }) + .option('no-tool', { + type: 'string', + array: true, + description: 'Exclude tools matching the specified names', + }) + .option('no-resource', { + type: 'string', + array: true, + description: 'Exclude tools matching the specified resources', + }) + .option('no-operation', { + type: 'string', + array: true, + description: 'Exclude tools matching the specified operations', + }) + .option('no-tag', { + type: 'string', + array: true, + description: 'Exclude tools with the specified tags', + }) + .option('list', { + type: 'boolean', + description: 'List all tools and exit', + }) + .option('client', { + type: 'string', + choices: Object.keys(CLIENT_PRESETS), + description: 'Specify the MCP client being used', + }) + .option('capability', { + type: 'string', + array: true, + description: 'Specify client capabilities', + coerce: (values: string[]) => { + return values.flatMap((v) => v.split(',')); + }, + }) + .option('no-capability', { + type: 'string', + array: true, + description: 'Unset client capabilities', + choices: CAPABILITY_CHOICES, + coerce: (values: string[]) => { + return values.flatMap((v) => v.split(',')); + }, + }) + .option('describe-capabilities', { + type: 'boolean', + description: 'Print detailed explanation of client capabilities and exit', + }) + .help(); + + for (const [command, desc] of examples()) { + opts.example(command, desc); + } + + const argv = opts.parseSync(); + + // Handle describe-capabilities flag + if (argv.describeCapabilities) { + console.log(getCapabilitiesExplanation()); + process.exit(0); + } + + const filters: Filter[] = []; + + // Helper function to support comma-separated values + const splitValues = (values: string[] | undefined): string[] => { + if (!values) return []; + return values.flatMap((v) => v.split(',')); + }; + + for (const tag of splitValues(argv.tag)) { + filters.push({ type: 'tag', op: 'include', value: tag }); + } + + for (const tag of splitValues(argv.noTag)) { + filters.push({ type: 'tag', op: 'exclude', value: tag }); + } + + for (const resource of splitValues(argv.resource)) { + filters.push({ type: 'resource', op: 'include', value: resource }); + } + + for (const resource of splitValues(argv.noResource)) { + filters.push({ type: 'resource', op: 'exclude', value: resource }); + } + + for (const tool of splitValues(argv.tool)) { + filters.push({ type: 'tool', op: 'include', value: tool }); + } + + for (const tool of splitValues(argv.noTool)) { + filters.push({ type: 'tool', op: 'exclude', value: tool }); + } + + for (const operation of splitValues(argv.operation)) { + filters.push({ type: 'operation', op: 'include', value: operation }); + } + + for (const operation of splitValues(argv.noOperation)) { + filters.push({ type: 'operation', op: 'exclude', value: operation }); + } + + // Parse client capabilities + const clientCapabilities: ClientCapabilities = { + topLevelUnions: true, + validJson: true, + refs: true, + unions: true, + formats: true, + toolNameLength: undefined, + }; + + // Apply client preset if specified + if (typeof argv.client === 'string') { + const clientKey = argv.client as ClientType; + if (CLIENT_PRESETS[clientKey]) { + Object.assign(clientCapabilities, CLIENT_PRESETS[clientKey]); + } + } + + // Apply individual capability overrides + if (Array.isArray(argv.capability)) { + for (const cap of argv.capability) { + const parsedCap = parseCapabilityValue(cap); + if (parsedCap.name === 'top-level-unions') { + clientCapabilities.topLevelUnions = true; + } else if (parsedCap.name === 'valid-json') { + clientCapabilities.validJson = true; + } else if (parsedCap.name === 'refs') { + clientCapabilities.refs = true; + } else if (parsedCap.name === 'unions') { + clientCapabilities.unions = true; + } else if (parsedCap.name === 'formats') { + clientCapabilities.formats = true; + } else if (parsedCap.name === 'tool-name-length') { + clientCapabilities.toolNameLength = parsedCap.value; + } + } + } + + // Handle no-capability options to unset capabilities + if (Array.isArray(argv.noCapability)) { + for (const cap of argv.noCapability) { + if (cap === 'top-level-unions') { + clientCapabilities.topLevelUnions = false; + } else if (cap === 'valid-json') { + clientCapabilities.validJson = false; + } else if (cap === 'refs') { + clientCapabilities.refs = false; + } else if (cap === 'unions') { + clientCapabilities.unions = false; + } else if (cap === 'formats') { + clientCapabilities.formats = false; + } else if (cap === 'tool-name-length') { + clientCapabilities.toolNameLength = undefined; + } + } + } + + const explicitTools = Boolean(argv.tools || argv.noTools); + const includeDynamicTools = + explicitTools ? argv.tools?.includes('dynamic') && !argv.noTools?.includes('dynamic') : undefined; + const includeAllTools = + explicitTools ? argv.tools?.includes('all') && !argv.noTools?.includes('all') : undefined; + + return { + includeDynamicTools, + includeAllTools, + filters, + capabilities: clientCapabilities, + list: argv.list || false, + }; +} + +function getCapabilitiesExplanation(): string { + return ` +Client Capabilities Explanation: + +Different Language Models (LLMs) and the MCP clients that use them have varying limitations in how they handle tool schemas. Capability flags allow you to inform the MCP server about these limitations. + +When a capability flag is set to false, the MCP server will automatically adjust the tool schemas to work around that limitation, ensuring broader compatibility. + +Available Capabilities: + +# top-level-unions +Some clients/LLMs do not support JSON schemas with a union type (anyOf) at the root level. If a client lacks this capability, the MCP server splits tools with top-level unions into multiple separate tools, one for each variant in the union. + +# refs +Some clients/LLMs do not support $ref pointers for schema reuse. If a client lacks this capability, the MCP server automatically inlines all references ($defs) directly into the schema. Properties that would cause circular references are removed during this process. + +# valid-json +Some clients/LLMs may incorrectly send arguments as a JSON-encoded string instead of a proper JSON object. If a client *has* this capability, the MCP server will attempt to parse string values as JSON if the initial validation against the schema fails. + +# unions +Some clients/LLMs do not support union types (anyOf) in JSON schemas. If a client lacks this capability, the MCP server removes all anyOf fields and uses only the first variant as the schema. + +# formats +Some clients/LLMs do not support the 'format' keyword in JSON Schema specifications. If a client lacks this capability, the MCP server removes all format fields and appends the format information to the field's description in parentheses. + +# tool-name-length=N +Some clients/LLMs impose a maximum length on tool names. If this capability is set, the MCP server will automatically truncate tool names exceeding the specified length (N), ensuring uniqueness by appending numbers if necessary. + +Client Presets (--client): +Presets like '--client=openai-agents' or '--client=cursor' automatically configure these capabilities based on current known limitations of those clients, simplifying setup. + +Current presets: +${JSON.stringify(CLIENT_PRESETS, null, 2)} + `; +} + +function examples(): [string, string][] { + const firstEndpoint = endpoints[0]!; + const secondEndpoint = + endpoints.find((e) => e.metadata.resource !== firstEndpoint.metadata.resource) || endpoints[1]; + const tag = endpoints.find((e) => e.metadata.tags.length > 0)?.metadata.tags[0]; + const otherEndpoint = secondEndpoint || firstEndpoint; + + return [ + [ + `--tool="${firstEndpoint.tool.name}" ${secondEndpoint ? `--tool="${secondEndpoint.tool.name}"` : ''}`, + 'Include tools by name', + ], + [ + `--resource="${firstEndpoint.metadata.resource}" --operation="read"`, + 'Filter by resource and operation', + ], + [ + `--resource="${otherEndpoint.metadata.resource}*" --no-tool="${otherEndpoint.tool.name}"`, + 'Use resource wildcards and exclusions', + ], + [`--client="cursor"`, 'Adjust schemas to be more compatible with Cursor'], + [ + `--capability="top-level-unions" --capability="tool-name-length=40"`, + 'Specify individual client capabilities', + ], + [ + `--client="cursor" --no-capability="tool-name-length"`, + 'Use cursor client preset but remove tool name length limit', + ], + ...(tag ? [[`--tag="${tag}"`, 'Filter based on tags'] as [string, string]] : []), + ]; +} diff --git a/packages/mcp-server/src/server.ts b/packages/mcp-server/src/server.ts new file mode 100644 index 0000000..30ba904 --- /dev/null +++ b/packages/mcp-server/src/server.ts @@ -0,0 +1,128 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { Server } from '@modelcontextprotocol/sdk/server/index.js'; +import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; +import { Endpoint, endpoints, HandlerFunction, query } from './tools'; +import { CallToolRequestSchema, ListToolsRequestSchema, Tool } from '@modelcontextprotocol/sdk/types.js'; +import ScanDocuments from 'scan-documents'; +import { + applyCompatibilityTransformations, + ClientCapabilities, + defaultClientCapabilities, + parseEmbeddedJSON, +} from './compat'; +import { dynamicTools } from './dynamic-tools'; +import { ParsedOptions } from './options'; +export { endpoints } from './tools'; + +// Create server instance +export const server = new McpServer( + { + name: 'scan_documents_api', + version: '0.1.0-alpha.1', + }, + { + capabilities: { + tools: {}, + }, + }, +); + +/** + * Initializes the provided MCP Server with the given tools and handlers. + * If not provided, the default client, tools and handlers will be used. + */ +export function init(params: { + server: Server | McpServer; + client?: ScanDocuments; + endpoints?: { tool: Tool; handler: HandlerFunction }[]; + capabilities?: Partial; +}) { + const server = params.server instanceof McpServer ? params.server.server : params.server; + const providedEndpoints = params.endpoints || endpoints; + + const endpointMap = Object.fromEntries(providedEndpoints.map((endpoint) => [endpoint.tool.name, endpoint])); + + const client = params.client || new ScanDocuments({}); + + server.setRequestHandler(ListToolsRequestSchema, async () => { + return { + tools: providedEndpoints.map((endpoint) => endpoint.tool), + }; + }); + + server.setRequestHandler(CallToolRequestSchema, async (request) => { + const { name, arguments: args } = request.params; + const endpoint = endpointMap[name]; + if (!endpoint) { + throw new Error(`Unknown tool: ${name}`); + } + + return executeHandler(endpoint.tool, endpoint.handler, client, args, params.capabilities); + }); +} + +/** + * Selects the tools to include in the MCP Server based on the provided options. + */ +export function selectTools(endpoints: Endpoint[], options: ParsedOptions) { + const filteredEndpoints = query(options.filters, endpoints); + + const includedTools = filteredEndpoints; + + if (options.includeAllTools && includedTools.length === 0) { + includedTools.push(...endpoints); + } + + if (options.includeDynamicTools) { + includedTools.push(...dynamicTools(endpoints)); + } + + if (includedTools.length === 0) { + includedTools.push(...endpoints); + } + + return applyCompatibilityTransformations(includedTools, options.capabilities); +} + +/** + * Runs the provided handler with the given client and arguments. + */ +export async function executeHandler( + tool: Tool, + handler: HandlerFunction, + client: ScanDocuments, + args: Record | undefined, + compatibilityOptions?: Partial, +) { + const options = { ...defaultClientCapabilities, ...compatibilityOptions }; + if (options.validJson && args) { + args = args = parseEmbeddedJSON(args, tool.inputSchema); + } + const result = await handler(client, args || {}); + return { + content: [ + { + type: 'text', + text: JSON.stringify(result, null, 2), + }, + ], + }; +} + +export const readEnv = (env: string): string | undefined => { + if (typeof (globalThis as any).process !== 'undefined') { + return (globalThis as any).process.env?.[env]?.trim(); + } else if (typeof (globalThis as any).Deno !== 'undefined') { + return (globalThis as any).Deno.env?.get?.(env)?.trim(); + } + return; +}; + +export const readEnvOrError = (env: string): string => { + let envValue = readEnv(env); + if (envValue === undefined) { + throw new Error(`Environment variable ${env} is not set`); + } + return envValue; +}; diff --git a/packages/mcp-server/src/tools.ts b/packages/mcp-server/src/tools.ts new file mode 100644 index 0000000..7e516de --- /dev/null +++ b/packages/mcp-server/src/tools.ts @@ -0,0 +1 @@ +export * from './tools/index'; diff --git a/packages/mcp-server/src/tools/events/list-events.ts b/packages/mcp-server/src/tools/events/list-events.ts new file mode 100644 index 0000000..09c1b70 --- /dev/null +++ b/packages/mcp-server/src/tools/events/list-events.ts @@ -0,0 +1,34 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { Tool } from '@modelcontextprotocol/sdk/types.js'; +import type { Metadata } from '../'; +import ScanDocuments from 'scan-documents'; + +export const metadata: Metadata = { + resource: 'events', + operation: 'read', + tags: [], +}; + +export const tool: Tool = { + name: 'list_events', + description: 'Retrieves a paginated list of events belonging to the authenticated user.', + inputSchema: { + type: 'object', + properties: { + from: { + type: 'string', + }, + take: { + type: 'number', + }, + }, + }, +}; + +export const handler = (client: ScanDocuments, args: Record | undefined) => { + const body = args as any; + return client.events.list(body); +}; + +export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/files/delete-files.ts b/packages/mcp-server/src/tools/files/delete-files.ts new file mode 100644 index 0000000..bfa290b --- /dev/null +++ b/packages/mcp-server/src/tools/files/delete-files.ts @@ -0,0 +1,31 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { Tool } from '@modelcontextprotocol/sdk/types.js'; +import type { Metadata } from '../'; +import ScanDocuments from 'scan-documents'; + +export const metadata: Metadata = { + resource: 'files', + operation: 'write', + tags: [], +}; + +export const tool: Tool = { + name: 'delete_files', + description: 'Deletes a specific file by its ID.', + inputSchema: { + type: 'object', + properties: { + id: { + type: 'string', + }, + }, + }, +}; + +export const handler = (client: ScanDocuments, args: Record | undefined) => { + const { id, ...body } = args as any; + return client.files.delete(id); +}; + +export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/files/download-files.ts b/packages/mcp-server/src/tools/files/download-files.ts new file mode 100644 index 0000000..cd8c759 --- /dev/null +++ b/packages/mcp-server/src/tools/files/download-files.ts @@ -0,0 +1,31 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { Tool } from '@modelcontextprotocol/sdk/types.js'; +import type { Metadata } from '../'; +import ScanDocuments from 'scan-documents'; + +export const metadata: Metadata = { + resource: 'files', + operation: 'read', + tags: [], +}; + +export const tool: Tool = { + name: 'download_files', + description: 'Downloads the content of a specific file by its ID.', + inputSchema: { + type: 'object', + properties: { + id: { + type: 'string', + }, + }, + }, +}; + +export const handler = (client: ScanDocuments, args: Record | undefined) => { + const { id, ...body } = args as any; + return client.files.download(id); +}; + +export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/files/list-files.ts b/packages/mcp-server/src/tools/files/list-files.ts new file mode 100644 index 0000000..6482460 --- /dev/null +++ b/packages/mcp-server/src/tools/files/list-files.ts @@ -0,0 +1,36 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { Tool } from '@modelcontextprotocol/sdk/types.js'; +import type { Metadata } from '../'; +import ScanDocuments from 'scan-documents'; + +export const metadata: Metadata = { + resource: 'files', + operation: 'read', + tags: [], +}; + +export const tool: Tool = { + name: 'list_files', + description: 'Retrieves a paginated list of files belonging to the authenticated user.', + inputSchema: { + type: 'object', + properties: { + from: { + type: 'string', + description: 'The id of the file from which to start the search', + }, + take: { + type: 'number', + description: 'The number of elements to retrieve', + }, + }, + }, +}; + +export const handler = (client: ScanDocuments, args: Record | undefined) => { + const body = args as any; + return client.files.list(body); +}; + +export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/files/retrieve-files.ts b/packages/mcp-server/src/tools/files/retrieve-files.ts new file mode 100644 index 0000000..de4ab3e --- /dev/null +++ b/packages/mcp-server/src/tools/files/retrieve-files.ts @@ -0,0 +1,31 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { Tool } from '@modelcontextprotocol/sdk/types.js'; +import type { Metadata } from '../'; +import ScanDocuments from 'scan-documents'; + +export const metadata: Metadata = { + resource: 'files', + operation: 'read', + tags: [], +}; + +export const tool: Tool = { + name: 'retrieve_files', + description: 'Retrieves the data for a specific file by its ID.', + inputSchema: { + type: 'object', + properties: { + id: { + type: 'string', + }, + }, + }, +}; + +export const handler = (client: ScanDocuments, args: Record | undefined) => { + const { id, ...body } = args as any; + return client.files.retrieve(id); +}; + +export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/files/upload-files.ts b/packages/mcp-server/src/tools/files/upload-files.ts new file mode 100644 index 0000000..6bc76b4 --- /dev/null +++ b/packages/mcp-server/src/tools/files/upload-files.ts @@ -0,0 +1,36 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { Tool } from '@modelcontextprotocol/sdk/types.js'; +import type { Metadata } from '../'; +import ScanDocuments from 'scan-documents'; + +export const metadata: Metadata = { + resource: 'files', + operation: 'write', + tags: [], +}; + +export const tool: Tool = { + name: 'upload_files', + description: "Uploads a file to the user's storage. The file size is limited to 10MB.", + inputSchema: { + type: 'object', + properties: { + file: { + type: 'string', + description: 'The file to upload', + }, + name: { + type: 'string', + description: 'The name of the file', + }, + }, + }, +}; + +export const handler = (client: ScanDocuments, args: Record | undefined) => { + const body = args as any; + return client.files.upload(body); +}; + +export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/image-operations/apply-effect-image-operations.ts b/packages/mcp-server/src/tools/image-operations/apply-effect-image-operations.ts new file mode 100644 index 0000000..6d2ac86 --- /dev/null +++ b/packages/mcp-server/src/tools/image-operations/apply-effect-image-operations.ts @@ -0,0 +1,41 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { Tool } from '@modelcontextprotocol/sdk/types.js'; +import type { Metadata } from '../'; +import ScanDocuments from 'scan-documents'; + +export const metadata: Metadata = { + resource: 'image_operations', + operation: 'write', + tags: [], +}; + +export const tool: Tool = { + name: 'apply_effect_image_operations', + description: 'Creates a task to apply a specified visual effect to an image.', + inputSchema: { + type: 'object', + properties: { + effect: { + type: 'string', + description: 'The effect to apply to the image', + enum: ['grayscale', 'scanner', 'black-background'], + }, + input: { + type: 'string', + description: 'The id of the file to operate on.', + }, + name: { + type: 'string', + description: 'The name of the file', + }, + }, + }, +}; + +export const handler = (client: ScanDocuments, args: Record | undefined) => { + const body = args as any; + return client.imageOperations.applyEffect(body); +}; + +export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/image-operations/convert-image-operations.ts b/packages/mcp-server/src/tools/image-operations/convert-image-operations.ts new file mode 100644 index 0000000..1cf1099 --- /dev/null +++ b/packages/mcp-server/src/tools/image-operations/convert-image-operations.ts @@ -0,0 +1,90 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { Tool } from '@modelcontextprotocol/sdk/types.js'; +import type { Metadata } from '../'; +import ScanDocuments from 'scan-documents'; + +export const metadata: Metadata = { + resource: 'image_operations', + operation: 'write', + tags: [], +}; + +export const tool: Tool = { + name: 'convert_image_operations', + description: 'Creates a task to convert an image file to a different format.', + inputSchema: { + type: 'object', + anyOf: [ + { + type: 'object', + properties: { + input: { + type: 'string', + description: 'The id of the file to operate on.', + }, + target_format: { + type: 'string', + description: 'The format to convert the image to.', + enum: ['image/png'], + }, + name: { + type: 'string', + description: 'The name of the file', + }, + }, + }, + { + type: 'object', + properties: { + input: { + type: 'string', + description: 'The id of the file to operate on.', + }, + quality: { + type: 'number', + description: 'Image quality (1-100) for lossy formats like jpeg.', + }, + target_format: { + type: 'string', + description: 'The format to convert the image to.', + enum: ['image/jpeg'], + }, + name: { + type: 'string', + description: 'The name of the file', + }, + }, + }, + { + type: 'object', + properties: { + input: { + type: 'string', + description: 'The id of the file to operate on.', + }, + quality: { + type: 'number', + description: 'Image quality (1-100) for lossy formats like webp.', + }, + target_format: { + type: 'string', + description: 'The format to convert the image to.', + enum: ['image/webp'], + }, + name: { + type: 'string', + description: 'The name of the file', + }, + }, + }, + ], + }, +}; + +export const handler = (client: ScanDocuments, args: Record | undefined) => { + const body = args as any; + return client.imageOperations.convert(body); +}; + +export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/image-operations/detect-documents-image-operations.ts b/packages/mcp-server/src/tools/image-operations/detect-documents-image-operations.ts new file mode 100644 index 0000000..b4c59a9 --- /dev/null +++ b/packages/mcp-server/src/tools/image-operations/detect-documents-image-operations.ts @@ -0,0 +1,32 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { Tool } from '@modelcontextprotocol/sdk/types.js'; +import type { Metadata } from '../'; +import ScanDocuments from 'scan-documents'; + +export const metadata: Metadata = { + resource: 'image_operations', + operation: 'write', + tags: [], +}; + +export const tool: Tool = { + name: 'detect_documents_image_operations', + description: 'Creates a task to detect document boundaries within an image.', + inputSchema: { + type: 'object', + properties: { + input: { + type: 'string', + description: 'The id of the file to operate on.', + }, + }, + }, +}; + +export const handler = (client: ScanDocuments, args: Record | undefined) => { + const body = args as any; + return client.imageOperations.detectDocuments(body); +}; + +export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/image-operations/extract-text-image-operations.ts b/packages/mcp-server/src/tools/image-operations/extract-text-image-operations.ts new file mode 100644 index 0000000..3c13c7f --- /dev/null +++ b/packages/mcp-server/src/tools/image-operations/extract-text-image-operations.ts @@ -0,0 +1,150 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { Tool } from '@modelcontextprotocol/sdk/types.js'; +import type { Metadata } from '../'; +import ScanDocuments from 'scan-documents'; + +export const metadata: Metadata = { + resource: 'image_operations', + operation: 'write', + tags: [], +}; + +export const tool: Tool = { + name: 'extract_text_image_operations', + description: 'Creates a task to extract text from a specified image file.', + inputSchema: { + type: 'object', + anyOf: [ + { + type: 'object', + properties: { + format: { + type: 'string', + description: 'The format of the text to be extracted.', + enum: ['plain'], + }, + input: { + type: 'string', + description: 'The id of the file to operate on.', + }, + }, + }, + { + type: 'object', + properties: { + format: { + type: 'string', + description: 'The format of the text to be extracted.', + enum: ['markdown'], + }, + input: { + type: 'string', + description: 'The id of the file to operate on.', + }, + }, + }, + { + type: 'object', + properties: { + format: { + type: 'string', + description: 'The format of the text to be extracted.', + enum: ['html'], + }, + input: { + type: 'string', + description: 'The id of the file to operate on.', + }, + }, + }, + { + type: 'object', + properties: { + format: { + type: 'string', + description: 'The format of the text to be extracted.', + enum: ['json'], + }, + input: { + type: 'string', + description: 'The id of the file to operate on.', + }, + schema: { + type: 'object', + description: + "An OpenAPI schema object describing the expected JSON structure. Required if format is 'json'.", + properties: { + description: { + type: 'string', + }, + example: { + type: 'object', + }, + format: { + type: 'string', + }, + items: { + $ref: '#/$defs/json_schema_spec', + }, + properties: { + type: 'object', + }, + required: { + type: 'array', + items: { + type: 'string', + }, + }, + type: { + type: 'string', + enum: ['string', 'number', 'integer', 'boolean', 'array', 'object'], + }, + }, + required: [], + }, + }, + }, + ], + $defs: { + json_schema_spec: { + type: 'object', + properties: { + description: { + type: 'string', + }, + example: { + type: 'object', + }, + format: { + type: 'string', + }, + items: { + $ref: '#/$defs/json_schema_spec', + }, + properties: { + type: 'object', + }, + required: { + type: 'array', + items: { + type: 'string', + }, + }, + type: { + type: 'string', + enum: ['string', 'number', 'integer', 'boolean', 'array', 'object'], + }, + }, + required: [], + }, + }, + }, +}; + +export const handler = (client: ScanDocuments, args: Record | undefined) => { + const body = args as any; + return client.imageOperations.extractText(body); +}; + +export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/image-operations/warp-image-operations.ts b/packages/mcp-server/src/tools/image-operations/warp-image-operations.ts new file mode 100644 index 0000000..6e546f9 --- /dev/null +++ b/packages/mcp-server/src/tools/image-operations/warp-image-operations.ts @@ -0,0 +1,44 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { Tool } from '@modelcontextprotocol/sdk/types.js'; +import type { Metadata } from '../'; +import ScanDocuments from 'scan-documents'; + +export const metadata: Metadata = { + resource: 'image_operations', + operation: 'write', + tags: [], +}; + +export const tool: Tool = { + name: 'warp_image_operations', + description: + 'Creates a task to apply perspective correction (warp) to an image based on detected document boundaries.', + inputSchema: { + type: 'object', + properties: { + input: { + type: 'string', + description: 'The id of the file to operate on.', + }, + vertices: { + type: 'array', + description: 'Coordinates of the 4 vertices of the quadrilateral to warp the image to.', + items: { + type: 'object', + }, + }, + name: { + type: 'string', + description: 'The name of the file', + }, + }, + }, +}; + +export const handler = (client: ScanDocuments, args: Record | undefined) => { + const body = args as any; + return client.imageOperations.warp(body); +}; + +export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/index.ts b/packages/mcp-server/src/tools/index.ts new file mode 100644 index 0000000..4ab0cd3 --- /dev/null +++ b/packages/mcp-server/src/tools/index.ts @@ -0,0 +1,118 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import ScanDocuments from 'scan-documents'; +import { Tool } from '@modelcontextprotocol/sdk/types.js'; + +import retrieve_files from './files/retrieve-files'; +import list_files from './files/list-files'; +import delete_files from './files/delete-files'; +import download_files from './files/download-files'; +import upload_files from './files/upload-files'; +import retrieve_tasks from './tasks/retrieve-tasks'; +import list_tasks from './tasks/list-tasks'; +import list_events from './events/list-events'; +import apply_effect_image_operations from './image-operations/apply-effect-image-operations'; +import convert_image_operations from './image-operations/convert-image-operations'; +import detect_documents_image_operations from './image-operations/detect-documents-image-operations'; +import extract_text_image_operations from './image-operations/extract-text-image-operations'; +import warp_image_operations from './image-operations/warp-image-operations'; +import extract_pages_pdf_operations from './pdf-operations/extract-pages-pdf-operations'; +import merge_pdf_operations from './pdf-operations/merge-pdf-operations'; +import render_pdf_operations from './pdf-operations/render-pdf-operations'; +import split_pdf_operations from './pdf-operations/split-pdf-operations'; + +export type HandlerFunction = ( + client: ScanDocuments, + args: Record | undefined, +) => Promise; + +export type Metadata = { + resource: string; + operation: 'read' | 'write'; + tags: string[]; +}; + +export type Endpoint = { + metadata: Metadata; + tool: Tool; + handler: HandlerFunction; +}; + +export const endpoints: Endpoint[] = []; + +function addEndpoint(endpoint: Endpoint) { + endpoints.push(endpoint); +} + +addEndpoint(retrieve_files); +addEndpoint(list_files); +addEndpoint(delete_files); +addEndpoint(download_files); +addEndpoint(upload_files); +addEndpoint(retrieve_tasks); +addEndpoint(list_tasks); +addEndpoint(list_events); +addEndpoint(apply_effect_image_operations); +addEndpoint(convert_image_operations); +addEndpoint(detect_documents_image_operations); +addEndpoint(extract_text_image_operations); +addEndpoint(warp_image_operations); +addEndpoint(extract_pages_pdf_operations); +addEndpoint(merge_pdf_operations); +addEndpoint(render_pdf_operations); +addEndpoint(split_pdf_operations); + +export type Filter = { + type: 'resource' | 'operation' | 'tag' | 'tool'; + op: 'include' | 'exclude'; + value: string; +}; + +export function query(filters: Filter[], endpoints: Endpoint[]): Endpoint[] { + const allExcludes = filters.length > 0 && filters.every((filter) => filter.op === 'exclude'); + const unmatchedFilters = new Set(filters); + + const filtered = endpoints.filter((endpoint: Endpoint) => { + let included = false || allExcludes; + + for (const filter of filters) { + if (match(filter, endpoint)) { + unmatchedFilters.delete(filter); + included = filter.op === 'include'; + } + } + + return included; + }); + + // Check if any filters didn't match + if (unmatchedFilters.size > 0) { + throw new Error( + `The following filters did not match any endpoints: ${[...unmatchedFilters] + .map((f) => `${f.type}=${f.value}`) + .join(', ')}`, + ); + } + + return filtered; +} + +function match({ type, value }: Filter, endpoint: Endpoint): boolean { + switch (type) { + case 'resource': { + const regexStr = '^' + normalizeResource(value).replace(/\*/g, '.*') + '$'; + const regex = new RegExp(regexStr); + return regex.test(normalizeResource(endpoint.metadata.resource)); + } + case 'operation': + return endpoint.metadata.operation === value; + case 'tag': + return endpoint.metadata.tags.includes(value); + case 'tool': + return endpoint.tool.name === value; + } +} + +function normalizeResource(resource: string): string { + return resource.toLowerCase().replace(/[^a-z.*\-_]*/g, ''); +} diff --git a/packages/mcp-server/src/tools/pdf-operations/extract-pages-pdf-operations.ts b/packages/mcp-server/src/tools/pdf-operations/extract-pages-pdf-operations.ts new file mode 100644 index 0000000..7147b8c --- /dev/null +++ b/packages/mcp-server/src/tools/pdf-operations/extract-pages-pdf-operations.ts @@ -0,0 +1,40 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { Tool } from '@modelcontextprotocol/sdk/types.js'; +import type { Metadata } from '../'; +import ScanDocuments from 'scan-documents'; + +export const metadata: Metadata = { + resource: 'pdf_operations', + operation: 'write', + tags: [], +}; + +export const tool: Tool = { + name: 'extract_pages_pdf_operations', + description: 'Creates a task to extract specific pages from a PDF file into a new PDF file.', + inputSchema: { + type: 'object', + properties: { + input: { + type: 'string', + description: 'The id of the file to operate on.', + }, + pages: { + type: 'string', + description: 'Page range (e.g., 2-7), a comma-separated list (e.g., 2,3,7) of pages.', + }, + name: { + type: 'string', + description: 'The name of the file', + }, + }, + }, +}; + +export const handler = (client: ScanDocuments, args: Record | undefined) => { + const body = args as any; + return client.pdfOperations.extractPages(body); +}; + +export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/pdf-operations/merge-pdf-operations.ts b/packages/mcp-server/src/tools/pdf-operations/merge-pdf-operations.ts new file mode 100644 index 0000000..d543d4f --- /dev/null +++ b/packages/mcp-server/src/tools/pdf-operations/merge-pdf-operations.ts @@ -0,0 +1,40 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { Tool } from '@modelcontextprotocol/sdk/types.js'; +import type { Metadata } from '../'; +import ScanDocuments from 'scan-documents'; + +export const metadata: Metadata = { + resource: 'pdf_operations', + operation: 'write', + tags: [], +}; + +export const tool: Tool = { + name: 'merge_pdf_operations', + description: 'Creates a task to merge multiple PDF and/or image files into a single PDF file.', + inputSchema: { + type: 'object', + properties: { + input: { + type: 'array', + description: 'The list of ids of the files to be merged', + items: { + type: 'string', + description: 'The id of the file to operate on.', + }, + }, + name: { + type: 'string', + description: 'The name of the file', + }, + }, + }, +}; + +export const handler = (client: ScanDocuments, args: Record | undefined) => { + const body = args as any; + return client.pdfOperations.merge(body); +}; + +export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/pdf-operations/render-pdf-operations.ts b/packages/mcp-server/src/tools/pdf-operations/render-pdf-operations.ts new file mode 100644 index 0000000..34e43c2 --- /dev/null +++ b/packages/mcp-server/src/tools/pdf-operations/render-pdf-operations.ts @@ -0,0 +1,44 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { Tool } from '@modelcontextprotocol/sdk/types.js'; +import type { Metadata } from '../'; +import ScanDocuments from 'scan-documents'; + +export const metadata: Metadata = { + resource: 'pdf_operations', + operation: 'write', + tags: [], +}; + +export const tool: Tool = { + name: 'render_pdf_operations', + description: 'Creates a task to render specified pages of a PDF file as images.', + inputSchema: { + type: 'object', + properties: { + input: { + type: 'string', + description: 'The id of the file to operate on.', + }, + dpi: { + type: 'integer', + description: 'Dots per inch (DPI) for the rendered image. Default is 300.', + }, + name: { + type: 'string', + description: 'The name of the file', + }, + pages: { + type: 'string', + description: 'Page range (e.g., 2-7), a comma-separated list (e.g., 2,3,7) of pages.', + }, + }, + }, +}; + +export const handler = (client: ScanDocuments, args: Record | undefined) => { + const body = args as any; + return client.pdfOperations.render(body); +}; + +export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/pdf-operations/split-pdf-operations.ts b/packages/mcp-server/src/tools/pdf-operations/split-pdf-operations.ts new file mode 100644 index 0000000..2aca4c6 --- /dev/null +++ b/packages/mcp-server/src/tools/pdf-operations/split-pdf-operations.ts @@ -0,0 +1,36 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { Tool } from '@modelcontextprotocol/sdk/types.js'; +import type { Metadata } from '../'; +import ScanDocuments from 'scan-documents'; + +export const metadata: Metadata = { + resource: 'pdf_operations', + operation: 'write', + tags: [], +}; + +export const tool: Tool = { + name: 'split_pdf_operations', + description: 'Creates a task to split a PDF file into multiple single-page PDF files.', + inputSchema: { + type: 'object', + properties: { + input: { + type: 'string', + description: 'The id of the file to operate on.', + }, + name: { + type: 'string', + description: 'The name of the file', + }, + }, + }, +}; + +export const handler = (client: ScanDocuments, args: Record | undefined) => { + const body = args as any; + return client.pdfOperations.split(body); +}; + +export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/tasks/list-tasks.ts b/packages/mcp-server/src/tools/tasks/list-tasks.ts new file mode 100644 index 0000000..1d0182f --- /dev/null +++ b/packages/mcp-server/src/tools/tasks/list-tasks.ts @@ -0,0 +1,34 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { Tool } from '@modelcontextprotocol/sdk/types.js'; +import type { Metadata } from '../'; +import ScanDocuments from 'scan-documents'; + +export const metadata: Metadata = { + resource: 'tasks', + operation: 'read', + tags: [], +}; + +export const tool: Tool = { + name: 'list_tasks', + description: 'Retrieves a paginated list of tasks belonging to the authenticated user.', + inputSchema: { + type: 'object', + properties: { + from: { + type: 'string', + }, + take: { + type: 'number', + }, + }, + }, +}; + +export const handler = (client: ScanDocuments, args: Record | undefined) => { + const body = args as any; + return client.tasks.list(body); +}; + +export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/tasks/retrieve-tasks.ts b/packages/mcp-server/src/tools/tasks/retrieve-tasks.ts new file mode 100644 index 0000000..3b422de --- /dev/null +++ b/packages/mcp-server/src/tools/tasks/retrieve-tasks.ts @@ -0,0 +1,32 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { Tool } from '@modelcontextprotocol/sdk/types.js'; +import type { Metadata } from '../'; +import ScanDocuments from 'scan-documents'; + +export const metadata: Metadata = { + resource: 'tasks', + operation: 'read', + tags: [], +}; + +export const tool: Tool = { + name: 'retrieve_tasks', + description: 'Retrieves the data for a specific task by its ID.', + inputSchema: { + type: 'object', + properties: { + id: { + type: 'string', + description: 'The id of the task to get.', + }, + }, + }, +}; + +export const handler = (client: ScanDocuments, args: Record | undefined) => { + const { id, ...body } = args as any; + return client.tasks.retrieve(id); +}; + +export default { metadata, tool, handler }; diff --git a/packages/mcp-server/tests/compat.test.ts b/packages/mcp-server/tests/compat.test.ts new file mode 100644 index 0000000..034b35c --- /dev/null +++ b/packages/mcp-server/tests/compat.test.ts @@ -0,0 +1,1068 @@ +import { + truncateToolNames, + removeTopLevelUnions, + removeAnyOf, + inlineRefs, + applyCompatibilityTransformations, + removeFormats, +} from '../src/compat'; +import { Tool } from '@modelcontextprotocol/sdk/types.js'; +import { JSONSchema } from '../src/compat'; +import { Endpoint } from '../src/tools'; + +describe('truncateToolNames', () => { + it('should return original names when maxLength is 0 or negative', () => { + const names = ['tool1', 'tool2', 'tool3']; + expect(truncateToolNames(names, 0)).toEqual(new Map()); + expect(truncateToolNames(names, -1)).toEqual(new Map()); + }); + + it('should return original names when all names are shorter than maxLength', () => { + const names = ['tool1', 'tool2', 'tool3']; + expect(truncateToolNames(names, 10)).toEqual(new Map()); + }); + + it('should truncate names longer than maxLength', () => { + const names = ['very-long-tool-name', 'another-long-tool-name', 'short']; + expect(truncateToolNames(names, 10)).toEqual( + new Map([ + ['very-long-tool-name', 'very-long-'], + ['another-long-tool-name', 'another-lo'], + ]), + ); + }); + + it('should handle duplicate truncated names by appending numbers', () => { + const names = ['tool-name-a', 'tool-name-b', 'tool-name-c']; + expect(truncateToolNames(names, 8)).toEqual( + new Map([ + ['tool-name-a', 'tool-na1'], + ['tool-name-b', 'tool-na2'], + ['tool-name-c', 'tool-na3'], + ]), + ); + }); +}); + +describe('removeTopLevelUnions', () => { + const createTestTool = (overrides = {}): Tool => ({ + name: 'test-tool', + description: 'Test tool', + inputSchema: { + type: 'object', + properties: {}, + }, + ...overrides, + }); + + it('should return the original tool if it has no anyOf at the top level', () => { + const tool = createTestTool({ + inputSchema: { + type: 'object', + properties: { + foo: { type: 'string' }, + }, + }, + }); + + expect(removeTopLevelUnions(tool)).toEqual([tool]); + }); + + it('should split a tool with top-level anyOf into multiple tools', () => { + const tool = createTestTool({ + name: 'union-tool', + description: 'A tool with unions', + inputSchema: { + type: 'object', + properties: { + common: { type: 'string' }, + }, + anyOf: [ + { + title: 'first variant', + description: 'Its the first variant', + properties: { + variant1: { type: 'string' }, + }, + required: ['variant1'], + }, + { + title: 'second variant', + properties: { + variant2: { type: 'number' }, + }, + required: ['variant2'], + }, + ], + }, + }); + + const result = removeTopLevelUnions(tool); + + expect(result).toEqual([ + { + name: 'union-tool_first_variant', + description: 'Its the first variant', + inputSchema: { + type: 'object', + title: 'first variant', + description: 'Its the first variant', + properties: { + common: { type: 'string' }, + variant1: { type: 'string' }, + }, + required: ['variant1'], + }, + }, + { + name: 'union-tool_second_variant', + description: 'A tool with unions', + inputSchema: { + type: 'object', + title: 'second variant', + description: 'A tool with unions', + properties: { + common: { type: 'string' }, + variant2: { type: 'number' }, + }, + required: ['variant2'], + }, + }, + ]); + }); + + it('should handle $defs and only include those used by the variant', () => { + const tool = createTestTool({ + name: 'defs-tool', + description: 'A tool with $defs', + inputSchema: { + type: 'object', + properties: { + common: { type: 'string' }, + }, + $defs: { + def1: { type: 'string', format: 'email' }, + def2: { type: 'number', minimum: 0 }, + unused: { type: 'boolean' }, + }, + anyOf: [ + { + properties: { + email: { $ref: '#/$defs/def1' }, + }, + }, + { + properties: { + count: { $ref: '#/$defs/def2' }, + }, + }, + ], + }, + }); + + const result = removeTopLevelUnions(tool); + + expect(result).toEqual([ + { + name: 'defs-tool_variant1', + description: 'A tool with $defs', + inputSchema: { + type: 'object', + description: 'A tool with $defs', + properties: { + common: { type: 'string' }, + email: { $ref: '#/$defs/def1' }, + }, + $defs: { + def1: { type: 'string', format: 'email' }, + }, + }, + }, + { + name: 'defs-tool_variant2', + description: 'A tool with $defs', + inputSchema: { + type: 'object', + description: 'A tool with $defs', + properties: { + common: { type: 'string' }, + count: { $ref: '#/$defs/def2' }, + }, + $defs: { + def2: { type: 'number', minimum: 0 }, + }, + }, + }, + ]); + }); +}); + +describe('removeAnyOf', () => { + it('should return original schema if it has no anyOf', () => { + const schema = { + type: 'object', + properties: { + foo: { type: 'string' }, + bar: { type: 'number' }, + }, + }; + + expect(removeAnyOf(schema)).toEqual(schema); + }); + + it('should remove anyOf field and use the first variant', () => { + const schema = { + type: 'object', + properties: { + common: { type: 'string' }, + }, + anyOf: [ + { + properties: { + variant1: { type: 'string' }, + }, + required: ['variant1'], + }, + { + properties: { + variant2: { type: 'number' }, + }, + required: ['variant2'], + }, + ], + }; + + const expected = { + type: 'object', + properties: { + common: { type: 'string' }, + variant1: { type: 'string' }, + }, + required: ['variant1'], + }; + + expect(removeAnyOf(schema)).toEqual(expected); + }); + + it('should recursively remove anyOf fields from nested properties', () => { + const schema = { + type: 'object', + properties: { + foo: { type: 'string' }, + nested: { + type: 'object', + properties: { + bar: { type: 'number' }, + }, + anyOf: [ + { + properties: { + option1: { type: 'boolean' }, + }, + }, + { + properties: { + option2: { type: 'array' }, + }, + }, + ], + }, + }, + }; + + const expected = { + type: 'object', + properties: { + foo: { type: 'string' }, + nested: { + type: 'object', + properties: { + bar: { type: 'number' }, + option1: { type: 'boolean' }, + }, + }, + }, + }; + + expect(removeAnyOf(schema)).toEqual(expected); + }); + + it('should handle arrays', () => { + const schema = { + type: 'object', + properties: { + items: { + type: 'array', + items: { + anyOf: [{ type: 'string' }, { type: 'number' }], + }, + }, + }, + }; + + const expected = { + type: 'object', + properties: { + items: { + type: 'array', + items: { + type: 'string', + }, + }, + }, + }; + + expect(removeAnyOf(schema)).toEqual(expected); + }); +}); + +describe('inlineRefs', () => { + it('should return the original schema if it does not contain $refs', () => { + const schema: JSONSchema = { + type: 'object', + properties: { + name: { type: 'string' }, + age: { type: 'number' }, + }, + }; + + expect(inlineRefs(schema)).toEqual(schema); + }); + + it('should inline simple $refs', () => { + const schema: JSONSchema = { + type: 'object', + properties: { + user: { $ref: '#/$defs/user' }, + }, + $defs: { + user: { + type: 'object', + properties: { + name: { type: 'string' }, + email: { type: 'string' }, + }, + }, + }, + }; + + const expected: JSONSchema = { + type: 'object', + properties: { + user: { + type: 'object', + properties: { + name: { type: 'string' }, + email: { type: 'string' }, + }, + }, + }, + }; + + expect(inlineRefs(schema)).toEqual(expected); + }); + + it('should inline nested $refs', () => { + const schema: JSONSchema = { + type: 'object', + properties: { + order: { $ref: '#/$defs/order' }, + }, + $defs: { + order: { + type: 'object', + properties: { + id: { type: 'string' }, + items: { type: 'array', items: { $ref: '#/$defs/item' } }, + }, + }, + item: { + type: 'object', + properties: { + product: { type: 'string' }, + quantity: { type: 'integer' }, + }, + }, + }, + }; + + const expected: JSONSchema = { + type: 'object', + properties: { + order: { + type: 'object', + properties: { + id: { type: 'string' }, + items: { + type: 'array', + items: { + type: 'object', + properties: { + product: { type: 'string' }, + quantity: { type: 'integer' }, + }, + }, + }, + }, + }, + }, + }; + + expect(inlineRefs(schema)).toEqual(expected); + }); + + it('should handle circular references by removing the circular part', () => { + const schema: JSONSchema = { + type: 'object', + properties: { + person: { $ref: '#/$defs/person' }, + }, + $defs: { + person: { + type: 'object', + properties: { + name: { type: 'string' }, + friend: { $ref: '#/$defs/person' }, // Circular reference + }, + }, + }, + }; + + const expected: JSONSchema = { + type: 'object', + properties: { + person: { + type: 'object', + properties: { + name: { type: 'string' }, + // friend property is removed to break the circular reference + }, + }, + }, + }; + + expect(inlineRefs(schema)).toEqual(expected); + }); + + it('should handle indirect circular references', () => { + const schema: JSONSchema = { + type: 'object', + properties: { + node: { $ref: '#/$defs/node' }, + }, + $defs: { + node: { + type: 'object', + properties: { + value: { type: 'string' }, + child: { $ref: '#/$defs/childNode' }, + }, + }, + childNode: { + type: 'object', + properties: { + value: { type: 'string' }, + parent: { $ref: '#/$defs/node' }, // Circular reference through childNode + }, + }, + }, + }; + + const expected: JSONSchema = { + type: 'object', + properties: { + node: { + type: 'object', + properties: { + value: { type: 'string' }, + child: { + type: 'object', + properties: { + value: { type: 'string' }, + // parent property is removed to break the circular reference + }, + }, + }, + }, + }, + }; + + expect(inlineRefs(schema)).toEqual(expected); + }); + + it('should preserve other properties when inlining references', () => { + const schema: JSONSchema = { + type: 'object', + properties: { + address: { $ref: '#/$defs/address', description: 'User address' }, + }, + $defs: { + address: { + type: 'object', + properties: { + street: { type: 'string' }, + city: { type: 'string' }, + }, + required: ['street'], + }, + }, + }; + + const expected: JSONSchema = { + type: 'object', + properties: { + address: { + type: 'object', + description: 'User address', + properties: { + street: { type: 'string' }, + city: { type: 'string' }, + }, + required: ['street'], + }, + }, + }; + + expect(inlineRefs(schema)).toEqual(expected); + }); +}); + +describe('removeFormats', () => { + it('should return original schema if formats capability is true', () => { + const schema = { + type: 'object', + properties: { + date: { type: 'string', description: 'A date field', format: 'date' }, + email: { type: 'string', description: 'An email field', format: 'email' }, + }, + }; + + expect(removeFormats(schema, true)).toEqual(schema); + }); + + it('should move format to description when formats capability is false', () => { + const schema = { + type: 'object', + properties: { + date: { type: 'string', description: 'A date field', format: 'date' }, + email: { type: 'string', description: 'An email field', format: 'email' }, + }, + }; + + const expected = { + type: 'object', + properties: { + date: { type: 'string', description: 'A date field (format: "date")' }, + email: { type: 'string', description: 'An email field (format: "email")' }, + }, + }; + + expect(removeFormats(schema, false)).toEqual(expected); + }); + + it('should handle properties without description', () => { + const schema = { + type: 'object', + properties: { + date: { type: 'string', format: 'date' }, + }, + }; + + const expected = { + type: 'object', + properties: { + date: { type: 'string', description: '(format: "date")' }, + }, + }; + + expect(removeFormats(schema, false)).toEqual(expected); + }); + + it('should handle nested properties', () => { + const schema = { + type: 'object', + properties: { + user: { + type: 'object', + properties: { + created_at: { type: 'string', description: 'Creation date', format: 'date-time' }, + }, + }, + }, + }; + + const expected = { + type: 'object', + properties: { + user: { + type: 'object', + properties: { + created_at: { type: 'string', description: 'Creation date (format: "date-time")' }, + }, + }, + }, + }; + + expect(removeFormats(schema, false)).toEqual(expected); + }); + + it('should handle arrays of objects', () => { + const schema = { + type: 'object', + properties: { + dates: { + type: 'array', + items: { + type: 'object', + properties: { + start: { type: 'string', description: 'Start date', format: 'date' }, + end: { type: 'string', description: 'End date', format: 'date' }, + }, + }, + }, + }, + }; + + const expected = { + type: 'object', + properties: { + dates: { + type: 'array', + items: { + type: 'object', + properties: { + start: { type: 'string', description: 'Start date (format: "date")' }, + end: { type: 'string', description: 'End date (format: "date")' }, + }, + }, + }, + }, + }; + + expect(removeFormats(schema, false)).toEqual(expected); + }); + + it('should handle schemas with $defs', () => { + const schema = { + type: 'object', + properties: { + date: { type: 'string', description: 'A date field', format: 'date' }, + }, + $defs: { + timestamp: { + type: 'string', + description: 'A timestamp field', + format: 'date-time', + }, + }, + }; + + const expected = { + type: 'object', + properties: { + date: { type: 'string', description: 'A date field (format: "date")' }, + }, + $defs: { + timestamp: { + type: 'string', + description: 'A timestamp field (format: "date-time")', + }, + }, + }; + + expect(removeFormats(schema, false)).toEqual(expected); + }); +}); + +describe('applyCompatibilityTransformations', () => { + const createTestTool = (name: string, overrides = {}): Tool => ({ + name, + description: 'Test tool', + inputSchema: { + type: 'object', + properties: {}, + }, + ...overrides, + }); + + const createTestEndpoint = (tool: Tool): Endpoint => ({ + tool, + handler: jest.fn(), + metadata: { + resource: 'test', + operation: 'read' as const, + tags: [], + }, + }); + + it('should not modify endpoints when all capabilities are enabled', () => { + const tool = createTestTool('test-tool'); + const endpoints = [createTestEndpoint(tool)]; + + const capabilities = { + topLevelUnions: true, + validJson: true, + refs: true, + unions: true, + formats: true, + toolNameLength: undefined, + }; + + const transformed = applyCompatibilityTransformations(endpoints, capabilities); + expect(transformed).toEqual(endpoints); + }); + + it('should split tools with top-level unions when topLevelUnions is disabled', () => { + const tool = createTestTool('union-tool', { + inputSchema: { + type: 'object', + properties: { + common: { type: 'string' }, + }, + anyOf: [ + { + title: 'first variant', + properties: { + variant1: { type: 'string' }, + }, + }, + { + title: 'second variant', + properties: { + variant2: { type: 'number' }, + }, + }, + ], + }, + }); + + const endpoints = [createTestEndpoint(tool)]; + + const capabilities = { + topLevelUnions: false, + validJson: true, + refs: true, + unions: true, + formats: true, + toolNameLength: undefined, + }; + + const transformed = applyCompatibilityTransformations(endpoints, capabilities); + expect(transformed.length).toBe(2); + expect(transformed[0]!.tool.name).toBe('union-tool_first_variant'); + expect(transformed[1]!.tool.name).toBe('union-tool_second_variant'); + }); + + it('should handle variants without titles in removeTopLevelUnions', () => { + const tool = createTestTool('union-tool', { + inputSchema: { + type: 'object', + properties: { + common: { type: 'string' }, + }, + anyOf: [ + { + properties: { + variant1: { type: 'string' }, + }, + }, + { + properties: { + variant2: { type: 'number' }, + }, + }, + ], + }, + }); + + const endpoints = [createTestEndpoint(tool)]; + + const capabilities = { + topLevelUnions: false, + validJson: true, + refs: true, + unions: true, + formats: true, + toolNameLength: undefined, + }; + + const transformed = applyCompatibilityTransformations(endpoints, capabilities); + expect(transformed.length).toBe(2); + expect(transformed[0]!.tool.name).toBe('union-tool_variant1'); + expect(transformed[1]!.tool.name).toBe('union-tool_variant2'); + }); + + it('should truncate tool names when toolNameLength is set', () => { + const tools = [ + createTestTool('very-long-tool-name-that-exceeds-limit'), + createTestTool('another-long-tool-name-to-truncate'), + createTestTool('short-name'), + ]; + + const endpoints = tools.map(createTestEndpoint); + + const capabilities = { + topLevelUnions: true, + validJson: true, + refs: true, + unions: true, + formats: true, + toolNameLength: 20, + }; + + const transformed = applyCompatibilityTransformations(endpoints, capabilities); + expect(transformed[0]!.tool.name).toBe('very-long-tool-name-'); + expect(transformed[1]!.tool.name).toBe('another-long-tool-na'); + expect(transformed[2]!.tool.name).toBe('short-name'); + }); + + it('should inline refs when refs capability is disabled', () => { + const tool = createTestTool('ref-tool', { + inputSchema: { + type: 'object', + properties: { + user: { $ref: '#/$defs/user' }, + }, + $defs: { + user: { + type: 'object', + properties: { + name: { type: 'string' }, + email: { type: 'string' }, + }, + }, + }, + }, + }); + + const endpoints = [createTestEndpoint(tool)]; + + const capabilities = { + topLevelUnions: true, + validJson: true, + refs: false, + unions: true, + formats: true, + toolNameLength: undefined, + }; + + const transformed = applyCompatibilityTransformations(endpoints, capabilities); + const schema = transformed[0]!.tool.inputSchema as JSONSchema; + expect(schema.$defs).toBeUndefined(); + + if (schema.properties) { + expect(schema.properties['user']).toEqual({ + type: 'object', + properties: { + name: { type: 'string' }, + email: { type: 'string' }, + }, + }); + } + }); + + it('should preserve external refs when inlining', () => { + const tool = createTestTool('ref-tool', { + inputSchema: { + type: 'object', + properties: { + internal: { $ref: '#/$defs/internal' }, + external: { $ref: 'https://example.com/schemas/external.json' }, + }, + $defs: { + internal: { + type: 'object', + properties: { + name: { type: 'string' }, + }, + }, + }, + }, + }); + + const endpoints = [createTestEndpoint(tool)]; + + const capabilities = { + topLevelUnions: true, + validJson: true, + refs: false, + unions: true, + formats: true, + toolNameLength: undefined, + }; + + const transformed = applyCompatibilityTransformations(endpoints, capabilities); + const schema = transformed[0]!.tool.inputSchema as JSONSchema; + + if (schema.properties) { + expect(schema.properties['internal']).toEqual({ + type: 'object', + properties: { + name: { type: 'string' }, + }, + }); + expect(schema.properties['external']).toEqual({ + $ref: 'https://example.com/schemas/external.json', + }); + } + }); + + it('should remove anyOf fields when unions capability is disabled', () => { + const tool = createTestTool('union-tool', { + inputSchema: { + type: 'object', + properties: { + field: { + anyOf: [{ type: 'string' }, { type: 'number' }], + }, + }, + }, + }); + + const endpoints = [createTestEndpoint(tool)]; + + const capabilities = { + topLevelUnions: true, + validJson: true, + refs: true, + unions: false, + formats: true, + toolNameLength: undefined, + }; + + const transformed = applyCompatibilityTransformations(endpoints, capabilities); + const schema = transformed[0]!.tool.inputSchema as JSONSchema; + + if (schema.properties && schema.properties['field']) { + const field = schema.properties['field']; + expect(field.anyOf).toBeUndefined(); + expect(field.type).toBe('string'); + } + }); + + it('should correctly combine topLevelUnions and toolNameLength transformations', () => { + const tool = createTestTool('very-long-union-tool-name', { + inputSchema: { + type: 'object', + properties: { + common: { type: 'string' }, + }, + anyOf: [ + { + title: 'first variant', + properties: { + variant1: { type: 'string' }, + }, + }, + { + title: 'second variant', + properties: { + variant2: { type: 'number' }, + }, + }, + ], + }, + }); + + const endpoints = [createTestEndpoint(tool)]; + + const capabilities = { + topLevelUnions: false, + validJson: true, + refs: true, + unions: true, + formats: true, + toolNameLength: 20, + }; + + const transformed = applyCompatibilityTransformations(endpoints, capabilities); + expect(transformed.length).toBe(2); + + // Both names should be truncated because they exceed 20 characters + expect(transformed[0]!.tool.name).toBe('very-long-union-too1'); + expect(transformed[1]!.tool.name).toBe('very-long-union-too2'); + }); + + it('should correctly combine refs and unions transformations', () => { + const tool = createTestTool('complex-tool', { + inputSchema: { + type: 'object', + properties: { + user: { $ref: '#/$defs/user' }, + }, + $defs: { + user: { + type: 'object', + properties: { + preference: { + anyOf: [{ type: 'string' }, { type: 'number' }], + }, + }, + }, + }, + }, + }); + + const endpoints = [createTestEndpoint(tool)]; + + const capabilities = { + topLevelUnions: true, + validJson: true, + refs: false, + unions: false, + formats: true, + toolNameLength: undefined, + }; + + const transformed = applyCompatibilityTransformations(endpoints, capabilities); + const schema = transformed[0]!.tool.inputSchema as JSONSchema; + + // Refs should be inlined + expect(schema.$defs).toBeUndefined(); + + // Safely access nested properties + if (schema.properties && schema.properties['user']) { + const user = schema.properties['user']; + // User should be inlined + expect(user.type).toBe('object'); + + // AnyOf in the inlined user.preference should be removed + if (user.properties && user.properties['preference']) { + const preference = user.properties['preference']; + expect(preference.anyOf).toBeUndefined(); + expect(preference.type).toBe('string'); + } + } + }); + + it('should handle formats capability being false', () => { + const tool = createTestTool('format-tool', { + inputSchema: { + type: 'object', + properties: { + date: { type: 'string', description: 'A date', format: 'date' }, + }, + }, + }); + + const endpoints = [createTestEndpoint(tool)]; + + const capabilities = { + topLevelUnions: true, + validJson: true, + refs: true, + unions: true, + formats: false, + toolNameLength: undefined, + }; + + const transformed = applyCompatibilityTransformations(endpoints, capabilities); + const schema = transformed[0]!.tool.inputSchema as JSONSchema; + + if (schema.properties && schema.properties['date']) { + const dateField = schema.properties['date']; + expect(dateField['format']).toBeUndefined(); + expect(dateField['description']).toBe('A date (format: "date")'); + } + }); +}); diff --git a/packages/mcp-server/tests/dynamic-tools.test.ts b/packages/mcp-server/tests/dynamic-tools.test.ts new file mode 100644 index 0000000..c74ef4a --- /dev/null +++ b/packages/mcp-server/tests/dynamic-tools.test.ts @@ -0,0 +1,172 @@ +import { dynamicTools } from '../src/dynamic-tools'; +import { Endpoint } from '../src/tools'; + +describe('dynamicTools', () => { + const fakeClient = {} as any; + + const endpoints: Endpoint[] = [ + makeEndpoint('test_read_endpoint', 'test_resource', 'read', ['test']), + makeEndpoint('test_write_endpoint', 'test_resource', 'write', ['test']), + makeEndpoint('user_endpoint', 'user', 'read', ['user', 'admin']), + makeEndpoint('admin_endpoint', 'admin', 'write', ['admin']), + ]; + + const tools = dynamicTools(endpoints); + + describe('list_api_endpoints', () => { + const listEndpointsTool = tools.find((tool) => tool.tool.name === 'list_api_endpoints'); + + it('should return all endpoints when no search query is provided', async () => { + if (!listEndpointsTool) fail('list_api_endpoints tool not found'); + + const result = await listEndpointsTool.handler(fakeClient, {}); + + expect(result.tools).toHaveLength(endpoints.length); + expect(result.tools.map((t: { name: string }) => t.name)).toContain('test_read_endpoint'); + expect(result.tools.map((t: { name: string }) => t.name)).toContain('test_write_endpoint'); + expect(result.tools.map((t: { name: string }) => t.name)).toContain('user_endpoint'); + expect(result.tools.map((t: { name: string }) => t.name)).toContain('admin_endpoint'); + }); + + it('should filter endpoints by name', async () => { + if (!listEndpointsTool) fail('list_api_endpoints tool not found'); + + const result = await listEndpointsTool.handler(fakeClient, { search_query: 'user' }); + + expect(result.tools).toHaveLength(1); + expect(result.tools[0].name).toBe('user_endpoint'); + }); + + it('should filter endpoints by resource', async () => { + if (!listEndpointsTool) fail('list_api_endpoints tool not found'); + + const result = await listEndpointsTool.handler(fakeClient, { search_query: 'admin' }); + + expect(result.tools.some((t: { resource: string }) => t.resource === 'admin')).toBeTruthy(); + }); + + it('should filter endpoints by tag', async () => { + if (!listEndpointsTool) fail('list_api_endpoints tool not found'); + + const result = await listEndpointsTool.handler(fakeClient, { search_query: 'admin' }); + + expect(result.tools.some((t: { tags: string[] }) => t.tags.includes('admin'))).toBeTruthy(); + }); + + it('should be case insensitive in search', async () => { + if (!listEndpointsTool) fail('list_api_endpoints tool not found'); + + const result = await listEndpointsTool.handler(fakeClient, { search_query: 'ADMIN' }); + + expect(result.tools.length).toBeGreaterThan(0); + result.tools.forEach((tool: { name: string; resource: string; tags: string[] }) => { + expect( + tool.name.toLowerCase().includes('admin') || + tool.resource.toLowerCase().includes('admin') || + tool.tags.some((tag: string) => tag.toLowerCase().includes('admin')), + ).toBeTruthy(); + }); + }); + }); + + describe('get_api_endpoint_schema', () => { + const getEndpointSchemaTool = tools.find((tool) => tool.tool.name === 'get_api_endpoint_schema'); + + it('should return schema for existing endpoint', async () => { + if (!getEndpointSchemaTool) fail('get_api_endpoint_schema tool not found'); + + const result = await getEndpointSchemaTool.handler(fakeClient, { endpoint: 'test_read_endpoint' }); + + expect(result).toEqual(endpoints[0]?.tool); + }); + + it('should throw error for non-existent endpoint', async () => { + if (!getEndpointSchemaTool) fail('get_api_endpoint_schema tool not found'); + + await expect( + getEndpointSchemaTool.handler(fakeClient, { endpoint: 'non_existent_endpoint' }), + ).rejects.toThrow('Endpoint non_existent_endpoint not found'); + }); + + it('should throw error when no endpoint provided', async () => { + if (!getEndpointSchemaTool) fail('get_api_endpoint_schema tool not found'); + + await expect(getEndpointSchemaTool.handler(fakeClient, undefined)).rejects.toThrow( + 'No endpoint provided', + ); + }); + }); + + describe('invoke_api_endpoint', () => { + const invokeEndpointTool = tools.find((tool) => tool.tool.name === 'invoke_api_endpoint'); + + it('should successfully invoke endpoint with valid arguments', async () => { + if (!invokeEndpointTool) fail('invoke_api_endpoint tool not found'); + + const mockHandler = endpoints[0]?.handler as jest.Mock; + mockHandler.mockClear(); + + await invokeEndpointTool.handler(fakeClient, { + endpoint_name: 'test_read_endpoint', + args: { testParam: 'test value' }, + }); + + expect(mockHandler).toHaveBeenCalledWith(fakeClient, { testParam: 'test value' }); + }); + + it('should throw error for non-existent endpoint', async () => { + if (!invokeEndpointTool) fail('invoke_api_endpoint tool not found'); + + await expect( + invokeEndpointTool.handler(fakeClient, { + endpoint_name: 'non_existent_endpoint', + args: { testParam: 'test value' }, + }), + ).rejects.toThrow(/Endpoint non_existent_endpoint not found/); + }); + + it('should throw error when no arguments provided', async () => { + if (!invokeEndpointTool) fail('invoke_api_endpoint tool not found'); + + await expect(invokeEndpointTool.handler(fakeClient, undefined)).rejects.toThrow('No endpoint provided'); + }); + + it('should throw error for invalid argument schema', async () => { + if (!invokeEndpointTool) fail('invoke_api_endpoint tool not found'); + + await expect( + invokeEndpointTool.handler(fakeClient, { + endpoint_name: 'test_read_endpoint', + args: { wrongParam: 'test value' }, // Missing required testParam + }), + ).rejects.toThrow(/Invalid arguments for endpoint/); + }); + }); +}); + +function makeEndpoint( + name: string, + resource: string, + operation: 'read' | 'write', + tags: string[] = [], +): Endpoint { + return { + metadata: { + resource, + operation, + tags, + }, + tool: { + name, + description: `Test endpoint for ${name}`, + inputSchema: { + type: 'object', + properties: { + testParam: { type: 'string' }, + }, + required: ['testParam'], + }, + }, + handler: jest.fn().mockResolvedValue({ success: true }), + }; +} diff --git a/packages/mcp-server/tests/options.test.ts b/packages/mcp-server/tests/options.test.ts new file mode 100644 index 0000000..9e2b2f8 --- /dev/null +++ b/packages/mcp-server/tests/options.test.ts @@ -0,0 +1,193 @@ +import { parseOptions } from '../src/options'; +import { Filter } from '../src/tools'; + +// Mock process.argv +const mockArgv = (args: string[]) => { + const originalArgv = process.argv; + process.argv = ['node', 'test.js', ...args]; + return () => { + process.argv = originalArgv; + }; +}; + +describe('parseOptions', () => { + it('should parse basic filter options', () => { + const cleanup = mockArgv([ + '--tool=test-tool', + '--resource=test-resource', + '--operation=read', + '--tag=test-tag', + ]); + + const result = parseOptions(); + + expect(result.filters).toEqual([ + { type: 'tag', op: 'include', value: 'test-tag' }, + { type: 'resource', op: 'include', value: 'test-resource' }, + { type: 'tool', op: 'include', value: 'test-tool' }, + { type: 'operation', op: 'include', value: 'read' }, + ] as Filter[]); + + // Default client capabilities + expect(result.capabilities).toEqual({ + topLevelUnions: true, + validJson: true, + refs: true, + unions: true, + formats: true, + toolNameLength: undefined, + }); + + expect(result.list).toBe(false); + + cleanup(); + }); + + it('should parse exclusion filters', () => { + const cleanup = mockArgv([ + '--no-tool=exclude-tool', + '--no-resource=exclude-resource', + '--no-operation=write', + '--no-tag=exclude-tag', + ]); + + const result = parseOptions(); + + expect(result.filters).toEqual([ + { type: 'tag', op: 'exclude', value: 'exclude-tag' }, + { type: 'resource', op: 'exclude', value: 'exclude-resource' }, + { type: 'tool', op: 'exclude', value: 'exclude-tool' }, + { type: 'operation', op: 'exclude', value: 'write' }, + ] as Filter[]); + + expect(result.capabilities).toEqual({ + topLevelUnions: true, + validJson: true, + refs: true, + unions: true, + formats: true, + toolNameLength: undefined, + }); + + cleanup(); + }); + + it('should parse client presets', () => { + const cleanup = mockArgv(['--client=openai-agents']); + + const result = parseOptions(); + + expect(result.capabilities).toEqual({ + topLevelUnions: false, + validJson: true, + refs: true, + unions: true, + formats: true, + toolNameLength: undefined, + }); + + cleanup(); + }); + + it('should parse individual capabilities', () => { + const cleanup = mockArgv([ + '--capability=top-level-unions', + '--capability=valid-json', + '--capability=refs', + '--capability=unions', + '--capability=tool-name-length=40', + ]); + + const result = parseOptions(); + + expect(result.capabilities).toEqual({ + topLevelUnions: true, + validJson: true, + refs: true, + unions: true, + formats: true, + toolNameLength: 40, + }); + + cleanup(); + }); + + it('should handle list option', () => { + const cleanup = mockArgv(['--list']); + + const result = parseOptions(); + + expect(result.list).toBe(true); + + cleanup(); + }); + + it('should handle multiple filters of the same type', () => { + const cleanup = mockArgv(['--tool=tool1', '--tool=tool2', '--resource=res1', '--resource=res2']); + + const result = parseOptions(); + + expect(result.filters).toEqual([ + { type: 'resource', op: 'include', value: 'res1' }, + { type: 'resource', op: 'include', value: 'res2' }, + { type: 'tool', op: 'include', value: 'tool1' }, + { type: 'tool', op: 'include', value: 'tool2' }, + ] as Filter[]); + + cleanup(); + }); + + it('should handle comma-separated values in array options', () => { + const cleanup = mockArgv([ + '--tool=tool1,tool2', + '--resource=res1,res2', + '--capability=top-level-unions,valid-json,unions', + ]); + + const result = parseOptions(); + + expect(result.filters).toEqual([ + { type: 'resource', op: 'include', value: 'res1' }, + { type: 'resource', op: 'include', value: 'res2' }, + { type: 'tool', op: 'include', value: 'tool1' }, + { type: 'tool', op: 'include', value: 'tool2' }, + ] as Filter[]); + + expect(result.capabilities).toEqual({ + topLevelUnions: true, + validJson: true, + refs: true, + unions: true, + formats: true, + toolNameLength: undefined, + }); + + cleanup(); + }); + + it('should handle invalid tool-name-length format', () => { + const cleanup = mockArgv(['--capability=tool-name-length=invalid']); + + // Mock console.error to prevent output during test + const originalError = console.error; + console.error = jest.fn(); + + expect(() => parseOptions()).toThrow(); + + console.error = originalError; + cleanup(); + }); + + it('should handle unknown capability', () => { + const cleanup = mockArgv(['--capability=unknown-capability']); + + // Mock console.error to prevent output during test + const originalError = console.error; + console.error = jest.fn(); + + expect(() => parseOptions()).toThrow(); + + console.error = originalError; + cleanup(); + }); +}); diff --git a/packages/mcp-server/tests/tools.test.ts b/packages/mcp-server/tests/tools.test.ts new file mode 100644 index 0000000..cfff24a --- /dev/null +++ b/packages/mcp-server/tests/tools.test.ts @@ -0,0 +1,225 @@ +import { Endpoint, Filter, Metadata, query } from '../src/tools'; + +describe('Endpoint filtering', () => { + const endpoints: Endpoint[] = [ + endpoint({ + resource: 'user', + operation: 'read', + tags: ['admin'], + toolName: 'retrieve_user', + }), + endpoint({ + resource: 'user.profile', + operation: 'write', + tags: [], + toolName: 'create_user_profile', + }), + endpoint({ + resource: 'user.profile', + operation: 'read', + tags: [], + toolName: 'get_user_profile', + }), + endpoint({ + resource: 'user.roles.permissions', + operation: 'write', + tags: ['admin', 'security'], + toolName: 'update_user_role_permissions', + }), + endpoint({ + resource: 'documents.metadata.tags', + operation: 'write', + tags: ['taxonomy', 'metadata'], + toolName: 'create_document_metadata_tags', + }), + endpoint({ + resource: 'organization.settings', + operation: 'read', + tags: ['admin', 'configuration'], + toolName: 'get_organization_settings', + }), + ]; + + const tests: { name: string; filters: Filter[]; expected: string[] }[] = [ + { + name: 'match none', + filters: [], + expected: [], + }, + + // Resource tests + { + name: 'simple resource', + filters: [{ type: 'resource', op: 'include', value: 'user' }], + expected: ['retrieve_user'], + }, + { + name: 'exclude resource', + filters: [{ type: 'resource', op: 'exclude', value: 'user' }], + expected: [ + 'create_user_profile', + 'get_user_profile', + 'update_user_role_permissions', + 'create_document_metadata_tags', + 'get_organization_settings', + ], + }, + { + name: 'resource and subresources', + filters: [{ type: 'resource', op: 'include', value: 'user*' }], + expected: ['retrieve_user', 'create_user_profile', 'get_user_profile', 'update_user_role_permissions'], + }, + { + name: 'just subresources', + filters: [{ type: 'resource', op: 'include', value: 'user.*' }], + expected: ['create_user_profile', 'get_user_profile', 'update_user_role_permissions'], + }, + { + name: 'specific subresource', + filters: [{ type: 'resource', op: 'include', value: 'user.roles.permissions' }], + expected: ['update_user_role_permissions'], + }, + { + name: 'deep wildcard match', + filters: [{ type: 'resource', op: 'include', value: '*.*.tags' }], + expected: ['create_document_metadata_tags'], + }, + + // Operation tests + { + name: 'read operation', + filters: [{ type: 'operation', op: 'include', value: 'read' }], + expected: ['retrieve_user', 'get_user_profile', 'get_organization_settings'], + }, + { + name: 'write operation', + filters: [{ type: 'operation', op: 'include', value: 'write' }], + expected: ['create_user_profile', 'update_user_role_permissions', 'create_document_metadata_tags'], + }, + { + name: 'resource and operation combined', + filters: [ + { type: 'resource', op: 'include', value: 'user.profile' }, + { type: 'operation', op: 'exclude', value: 'write' }, + ], + expected: ['get_user_profile'], + }, + + // Tag tests + { + name: 'admin tag', + filters: [{ type: 'tag', op: 'include', value: 'admin' }], + expected: ['retrieve_user', 'update_user_role_permissions', 'get_organization_settings'], + }, + { + name: 'taxonomy tag', + filters: [{ type: 'tag', op: 'include', value: 'taxonomy' }], + expected: ['create_document_metadata_tags'], + }, + { + name: 'multiple tags (OR logic)', + filters: [ + { type: 'tag', op: 'include', value: 'admin' }, + { type: 'tag', op: 'include', value: 'security' }, + ], + expected: ['retrieve_user', 'update_user_role_permissions', 'get_organization_settings'], + }, + { + name: 'excluding a tag', + filters: [ + { type: 'tag', op: 'include', value: 'admin' }, + { type: 'tag', op: 'exclude', value: 'security' }, + ], + expected: ['retrieve_user', 'get_organization_settings'], + }, + + // Tool name tests + { + name: 'tool name match', + filters: [{ type: 'tool', op: 'include', value: 'get_organization_settings' }], + expected: ['get_organization_settings'], + }, + { + name: 'two tools match', + filters: [ + { type: 'tool', op: 'include', value: 'get_organization_settings' }, + { type: 'tool', op: 'include', value: 'create_user_profile' }, + ], + expected: ['create_user_profile', 'get_organization_settings'], + }, + { + name: 'excluding tool by name', + filters: [ + { type: 'resource', op: 'include', value: 'user*' }, + { type: 'tool', op: 'exclude', value: 'retrieve_user' }, + ], + expected: ['create_user_profile', 'get_user_profile', 'update_user_role_permissions'], + }, + + // Complex combinations + { + name: 'complex filter: read operations with admin tag', + filters: [ + { type: 'operation', op: 'include', value: 'read' }, + { type: 'tag', op: 'include', value: 'admin' }, + ], + expected: [ + 'retrieve_user', + 'get_user_profile', + 'update_user_role_permissions', + 'get_organization_settings', + ], + }, + { + name: 'complex filter: user resources with no tags', + filters: [ + { type: 'resource', op: 'include', value: 'user.profile' }, + { type: 'tag', op: 'exclude', value: 'admin' }, + ], + expected: ['create_user_profile', 'get_user_profile'], + }, + { + name: 'complex filter: user resources and tags', + filters: [ + { type: 'resource', op: 'include', value: 'user.profile' }, + { type: 'tag', op: 'include', value: 'admin' }, + ], + expected: [ + 'retrieve_user', + 'create_user_profile', + 'get_user_profile', + 'update_user_role_permissions', + 'get_organization_settings', + ], + }, + ]; + + tests.forEach((test) => { + it(`filters by ${test.name}`, () => { + const filtered = query(test.filters, endpoints); + expect(filtered.map((e) => e.tool.name)).toEqual(test.expected); + }); + }); +}); + +function endpoint({ + resource, + operation, + tags, + toolName, +}: { + resource: string; + operation: Metadata['operation']; + tags: string[]; + toolName: string; +}): Endpoint { + return { + metadata: { + resource, + operation, + tags, + }, + tool: { name: toolName, inputSchema: { type: 'object', properties: {} } }, + handler: jest.fn(), + }; +} diff --git a/packages/mcp-server/tsc-multi.json b/packages/mcp-server/tsc-multi.json new file mode 100644 index 0000000..4facad5 --- /dev/null +++ b/packages/mcp-server/tsc-multi.json @@ -0,0 +1,7 @@ +{ + "targets": [ + { "extname": ".js", "module": "commonjs" }, + { "extname": ".mjs", "module": "esnext" } + ], + "projects": ["tsconfig.build.json"] +} diff --git a/packages/mcp-server/tsconfig.build.json b/packages/mcp-server/tsconfig.build.json new file mode 100644 index 0000000..9d1a592 --- /dev/null +++ b/packages/mcp-server/tsconfig.build.json @@ -0,0 +1,18 @@ +{ + "extends": "./tsconfig.json", + "include": ["dist/src"], + "exclude": [], + "compilerOptions": { + "rootDir": "./dist/src", + "paths": { + "scan-documents-mcp/*": ["dist/src/*"], + "scan-documents-mcp": ["dist/src/index.ts"] + }, + "noEmit": false, + "declaration": true, + "declarationMap": true, + "outDir": "dist", + "pretty": true, + "sourceMap": true + } +} diff --git a/packages/mcp-server/tsconfig.dist-src.json b/packages/mcp-server/tsconfig.dist-src.json new file mode 100644 index 0000000..e9f2d70 --- /dev/null +++ b/packages/mcp-server/tsconfig.dist-src.json @@ -0,0 +1,11 @@ +{ + // this config is included in the published src directory to prevent TS errors + // from appearing when users go to source, and VSCode opens the source .ts file + // via declaration maps + "include": ["index.ts"], + "compilerOptions": { + "target": "es2015", + "lib": ["DOM"], + "moduleResolution": "node" + } +} diff --git a/packages/mcp-server/tsconfig.json b/packages/mcp-server/tsconfig.json new file mode 100644 index 0000000..402ebc5 --- /dev/null +++ b/packages/mcp-server/tsconfig.json @@ -0,0 +1,37 @@ +{ + "include": ["src", "tests", "examples"], + "exclude": [], + "compilerOptions": { + "target": "es2020", + "lib": ["es2020"], + "module": "commonjs", + "moduleResolution": "node", + "esModuleInterop": true, + "baseUrl": "./", + "paths": { + "scan-documents-mcp/*": ["src/*"], + "scan-documents-mcp": ["src/index.ts"] + }, + "noEmit": true, + + "resolveJsonModule": true, + + "forceConsistentCasingInFileNames": true, + + "strict": true, + "noImplicitAny": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "strictBindCallApply": true, + "strictPropertyInitialization": true, + "noImplicitThis": true, + "noImplicitReturns": true, + "alwaysStrict": true, + "exactOptionalPropertyTypes": true, + "noUncheckedIndexedAccess": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + + "skipLibCheck": true + } +} diff --git a/packages/mcp-server/yarn.lock b/packages/mcp-server/yarn.lock new file mode 100644 index 0000000..9056173 --- /dev/null +++ b/packages/mcp-server/yarn.lock @@ -0,0 +1,3514 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@ampproject/remapping@^2.2.0": + version "2.3.0" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.3.0.tgz#ed441b6fa600072520ce18b43d2c8cc8caecc7f4" + integrity sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw== + dependencies: + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.24" + +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.27.1.tgz#200f715e66d52a23b221a9435534a91cc13ad5be" + integrity sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg== + dependencies: + "@babel/helper-validator-identifier" "^7.27.1" + js-tokens "^4.0.0" + picocolors "^1.1.1" + +"@babel/compat-data@^7.27.2": + version "7.27.2" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.27.2.tgz#4183f9e642fd84e74e3eea7ffa93a412e3b102c9" + integrity sha512-TUtMJYRPyUb/9aU8f3K0mjmjf6M9N5Woshn2CS6nqJSeJtTtQcpLUXjGt9vbF8ZGff0El99sWkLgzwW3VXnxZQ== + +"@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.23.9": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.27.1.tgz#89de51e86bd12246003e3524704c49541b16c3e6" + integrity sha512-IaaGWsQqfsQWVLqMn9OB92MNN7zukfVA4s7KKAI0KfrrDsZ0yhi5uV4baBuLuN7n3vsZpwP8asPPcVwApxvjBQ== + dependencies: + "@ampproject/remapping" "^2.2.0" + "@babel/code-frame" "^7.27.1" + "@babel/generator" "^7.27.1" + "@babel/helper-compilation-targets" "^7.27.1" + "@babel/helper-module-transforms" "^7.27.1" + "@babel/helpers" "^7.27.1" + "@babel/parser" "^7.27.1" + "@babel/template" "^7.27.1" + "@babel/traverse" "^7.27.1" + "@babel/types" "^7.27.1" + convert-source-map "^2.0.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.3" + semver "^6.3.1" + +"@babel/generator@^7.27.1", "@babel/generator@^7.7.2": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.27.1.tgz#862d4fad858f7208edd487c28b58144036b76230" + integrity sha512-UnJfnIpc/+JO0/+KRVQNGU+y5taA5vCbwN8+azkX6beii/ZF+enZJSOKo11ZSzGJjlNfJHfQtmQT8H+9TXPG2w== + dependencies: + "@babel/parser" "^7.27.1" + "@babel/types" "^7.27.1" + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.25" + jsesc "^3.0.2" + +"@babel/helper-compilation-targets@^7.27.1": + version "7.27.2" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz#46a0f6efab808d51d29ce96858dd10ce8732733d" + integrity sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ== + dependencies: + "@babel/compat-data" "^7.27.2" + "@babel/helper-validator-option" "^7.27.1" + browserslist "^4.24.0" + lru-cache "^5.1.1" + semver "^6.3.1" + +"@babel/helper-module-imports@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz#7ef769a323e2655e126673bb6d2d6913bbead204" + integrity sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w== + dependencies: + "@babel/traverse" "^7.27.1" + "@babel/types" "^7.27.1" + +"@babel/helper-module-transforms@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.27.1.tgz#e1663b8b71d2de948da5c4fb2a20ca4f3ec27a6f" + integrity sha512-9yHn519/8KvTU5BjTVEEeIM3w9/2yXNKoD82JifINImhpKkARMJKPP59kLo+BafpdN5zgNeIcS4jsGDmd3l58g== + dependencies: + "@babel/helper-module-imports" "^7.27.1" + "@babel/helper-validator-identifier" "^7.27.1" + "@babel/traverse" "^7.27.1" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.27.1", "@babel/helper-plugin-utils@^7.8.0": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz#ddb2f876534ff8013e6c2b299bf4d39b3c51d44c" + integrity sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw== + +"@babel/helper-string-parser@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz#54da796097ab19ce67ed9f88b47bb2ec49367687" + integrity sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA== + +"@babel/helper-validator-identifier@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz#a7054dcc145a967dd4dc8fee845a57c1316c9df8" + integrity sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow== + +"@babel/helper-validator-option@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz#fa52f5b1e7db1ab049445b421c4471303897702f" + integrity sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg== + +"@babel/helpers@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.27.1.tgz#ffc27013038607cdba3288e692c3611c06a18aa4" + integrity sha512-FCvFTm0sWV8Fxhpp2McP5/W53GPllQ9QeQ7SiqGWjMf/LVG07lFa5+pgK05IRhVwtvafT22KF+ZSnM9I545CvQ== + dependencies: + "@babel/template" "^7.27.1" + "@babel/types" "^7.27.1" + +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.27.1", "@babel/parser@^7.27.2": + version "7.27.2" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.27.2.tgz#577518bedb17a2ce4212afd052e01f7df0941127" + integrity sha512-QYLs8299NA7WM/bZAdp+CviYYkVoYXlDW2rzliy3chxd1PQjej7JORuMJDJXJUb9g0TT+B99EwaVLKmX+sPXWw== + dependencies: + "@babel/types" "^7.27.1" + +"@babel/plugin-syntax-async-generators@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-bigint@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea" + integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-class-properties@^7.12.13": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" + integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" + +"@babel/plugin-syntax-class-static-block@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz#195df89b146b4b78b3bf897fd7a257c84659d406" + integrity sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-import-attributes@^7.24.7": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.27.1.tgz#34c017d54496f9b11b61474e7ea3dfd5563ffe07" + integrity sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-syntax-import-meta@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" + integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-json-strings@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-jsx@^7.7.2": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.27.1.tgz#2f9beb5eff30fa507c5532d107daac7b888fa34c" + integrity sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/plugin-syntax-logical-assignment-operators@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" + integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-numeric-separator@^7.10.4": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" + integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-object-rest-spread@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-chaining@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-private-property-in-object@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz#0dc6671ec0ea22b6e94a1114f857970cd39de1ad" + integrity sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-top-level-await@^7.14.5": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" + integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-typescript@^7.7.2": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.27.1.tgz#5147d29066a793450f220c63fa3a9431b7e6dd18" + integrity sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + +"@babel/template@^7.27.1", "@babel/template@^7.3.3": + version "7.27.2" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.27.2.tgz#fa78ceed3c4e7b63ebf6cb39e5852fca45f6809d" + integrity sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw== + dependencies: + "@babel/code-frame" "^7.27.1" + "@babel/parser" "^7.27.2" + "@babel/types" "^7.27.1" + +"@babel/traverse@^7.27.1": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.27.1.tgz#4db772902b133bbddd1c4f7a7ee47761c1b9f291" + integrity sha512-ZCYtZciz1IWJB4U61UPu4KEaqyfj+r5T1Q5mqPo+IBpcG9kHv30Z0aD8LXPgC1trYa6rK0orRyAhqUgk4MjmEg== + dependencies: + "@babel/code-frame" "^7.27.1" + "@babel/generator" "^7.27.1" + "@babel/parser" "^7.27.1" + "@babel/template" "^7.27.1" + "@babel/types" "^7.27.1" + debug "^4.3.1" + globals "^11.1.0" + +"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.27.1", "@babel/types@^7.3.3": + version "7.27.1" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.27.1.tgz#9defc53c16fc899e46941fc6901a9eea1c9d8560" + integrity sha512-+EzkxvLNfiUeKMgy/3luqfsCWFRXLb7U6wNQTk60tovuckwB15B191tJWvpp4HjiQWdJkCxO3Wbvc6jlk3Xb2Q== + dependencies: + "@babel/helper-string-parser" "^7.27.1" + "@babel/helper-validator-identifier" "^7.27.1" + +"@bcoe/v8-coverage@^0.2.3": + version "0.2.3" + resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" + integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== + +"@cloudflare/cabidela@^0.2.4": + version "0.2.4" + resolved "https://registry.yarnpkg.com/@cloudflare/cabidela/-/cabidela-0.2.4.tgz#9a3e9212e636a24d796a8f16741c24885b326a1a" + integrity sha512-u/1OwwqfcMvjmUFOcb6QtFzVVGpncHJxwl254wjzp0JC5CUlBkV6r5BbRrHI5ZYJEAgu8NeeorirxngmMFPZjQ== + +"@cspotcode/source-map-support@^0.8.0": + version "0.8.1" + resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz#00629c35a688e05a88b1cda684fb9d5e73f000a1" + integrity sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw== + dependencies: + "@jridgewell/trace-mapping" "0.3.9" + +"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": + version "4.7.0" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz#607084630c6c033992a082de6e6fbc1a8b52175a" + integrity sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw== + dependencies: + eslint-visitor-keys "^3.4.3" + +"@eslint-community/regexpp@^4.10.0", "@eslint-community/regexpp@^4.6.1": + version "4.12.1" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.12.1.tgz#cfc6cffe39df390a3841cde2abccf92eaa7ae0e0" + integrity sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ== + +"@eslint/eslintrc@^2.1.4": + version "2.1.4" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz#388a269f0f25c1b6adc317b5a2c55714894c70ad" + integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^9.6.0" + globals "^13.19.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.57.1": + version "8.57.1" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.1.tgz#de633db3ec2ef6a3c89e2f19038063e8a122e2c2" + integrity sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q== + +"@humanwhocodes/config-array@^0.13.0": + version "0.13.0" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.13.0.tgz#fb907624df3256d04b9aa2df50d7aa97ec648748" + integrity sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw== + dependencies: + "@humanwhocodes/object-schema" "^2.0.3" + debug "^4.3.1" + minimatch "^3.0.5" + +"@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@^2.0.3": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3" + integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA== + +"@istanbuljs/load-nyc-config@^1.0.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" + integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== + dependencies: + camelcase "^5.3.1" + find-up "^4.1.0" + get-package-type "^0.1.0" + js-yaml "^3.13.1" + resolve-from "^5.0.0" + +"@istanbuljs/schema@^0.1.2", "@istanbuljs/schema@^0.1.3": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" + integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== + +"@jest/console@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-29.7.0.tgz#cd4822dbdb84529265c5a2bdb529a3c9cc950ffc" + integrity sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg== + dependencies: + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + slash "^3.0.0" + +"@jest/core@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-29.7.0.tgz#b6cccc239f30ff36609658c5a5e2291757ce448f" + integrity sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg== + dependencies: + "@jest/console" "^29.7.0" + "@jest/reporters" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + ci-info "^3.2.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + jest-changed-files "^29.7.0" + jest-config "^29.7.0" + jest-haste-map "^29.7.0" + jest-message-util "^29.7.0" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-resolve-dependencies "^29.7.0" + jest-runner "^29.7.0" + jest-runtime "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" + jest-watcher "^29.7.0" + micromatch "^4.0.4" + pretty-format "^29.7.0" + slash "^3.0.0" + strip-ansi "^6.0.0" + +"@jest/environment@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-29.7.0.tgz#24d61f54ff1f786f3cd4073b4b94416383baf2a7" + integrity sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw== + dependencies: + "@jest/fake-timers" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + jest-mock "^29.7.0" + +"@jest/expect-utils@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.7.0.tgz#023efe5d26a8a70f21677d0a1afc0f0a44e3a1c6" + integrity sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA== + dependencies: + jest-get-type "^29.6.3" + +"@jest/expect@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-29.7.0.tgz#76a3edb0cb753b70dfbfe23283510d3d45432bf2" + integrity sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ== + dependencies: + expect "^29.7.0" + jest-snapshot "^29.7.0" + +"@jest/fake-timers@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-29.7.0.tgz#fd91bf1fffb16d7d0d24a426ab1a47a49881a565" + integrity sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ== + dependencies: + "@jest/types" "^29.6.3" + "@sinonjs/fake-timers" "^10.0.2" + "@types/node" "*" + jest-message-util "^29.7.0" + jest-mock "^29.7.0" + jest-util "^29.7.0" + +"@jest/globals@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-29.7.0.tgz#8d9290f9ec47ff772607fa864ca1d5a2efae1d4d" + integrity sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/expect" "^29.7.0" + "@jest/types" "^29.6.3" + jest-mock "^29.7.0" + +"@jest/reporters@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-29.7.0.tgz#04b262ecb3b8faa83b0b3d321623972393e8f4c7" + integrity sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg== + dependencies: + "@bcoe/v8-coverage" "^0.2.3" + "@jest/console" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@jridgewell/trace-mapping" "^0.3.18" + "@types/node" "*" + chalk "^4.0.0" + collect-v8-coverage "^1.0.0" + exit "^0.1.2" + glob "^7.1.3" + graceful-fs "^4.2.9" + istanbul-lib-coverage "^3.0.0" + istanbul-lib-instrument "^6.0.0" + istanbul-lib-report "^3.0.0" + istanbul-lib-source-maps "^4.0.0" + istanbul-reports "^3.1.3" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + jest-worker "^29.7.0" + slash "^3.0.0" + string-length "^4.0.1" + strip-ansi "^6.0.0" + v8-to-istanbul "^9.0.1" + +"@jest/schemas@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.3.tgz#430b5ce8a4e0044a7e3819663305a7b3091c8e03" + integrity sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA== + dependencies: + "@sinclair/typebox" "^0.27.8" + +"@jest/source-map@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-29.6.3.tgz#d90ba772095cf37a34a5eb9413f1b562a08554c4" + integrity sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw== + dependencies: + "@jridgewell/trace-mapping" "^0.3.18" + callsites "^3.0.0" + graceful-fs "^4.2.9" + +"@jest/test-result@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-29.7.0.tgz#8db9a80aa1a097bb2262572686734baed9b1657c" + integrity sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA== + dependencies: + "@jest/console" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/istanbul-lib-coverage" "^2.0.0" + collect-v8-coverage "^1.0.0" + +"@jest/test-sequencer@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz#6cef977ce1d39834a3aea887a1726628a6f072ce" + integrity sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw== + dependencies: + "@jest/test-result" "^29.7.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + slash "^3.0.0" + +"@jest/transform@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-29.7.0.tgz#df2dd9c346c7d7768b8a06639994640c642e284c" + integrity sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw== + dependencies: + "@babel/core" "^7.11.6" + "@jest/types" "^29.6.3" + "@jridgewell/trace-mapping" "^0.3.18" + babel-plugin-istanbul "^6.1.1" + chalk "^4.0.0" + convert-source-map "^2.0.0" + fast-json-stable-stringify "^2.1.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + jest-regex-util "^29.6.3" + jest-util "^29.7.0" + micromatch "^4.0.4" + pirates "^4.0.4" + slash "^3.0.0" + write-file-atomic "^4.0.2" + +"@jest/types@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.6.3.tgz#1131f8cf634e7e84c5e77bab12f052af585fba59" + integrity sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw== + dependencies: + "@jest/schemas" "^29.6.3" + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^17.0.8" + chalk "^4.0.0" + +"@jridgewell/gen-mapping@^0.3.5": + version "0.3.8" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz#4f0e06362e01362f823d348f1872b08f666d8142" + integrity sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA== + dependencies: + "@jridgewell/set-array" "^1.2.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.24" + +"@jridgewell/resolve-uri@^3.0.3", "@jridgewell/resolve-uri@^3.1.0": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" + integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== + +"@jridgewell/set-array@^1.2.1": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280" + integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A== + +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz#3188bcb273a414b0d215fd22a58540b989b9409a" + integrity sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ== + +"@jridgewell/trace-mapping@0.3.9": + version "0.3.9" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9" + integrity sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ== + dependencies: + "@jridgewell/resolve-uri" "^3.0.3" + "@jridgewell/sourcemap-codec" "^1.4.10" + +"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25": + version "0.3.25" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0" + integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + +"@modelcontextprotocol/sdk@^1.6.1": + version "1.11.2" + resolved "https://registry.yarnpkg.com/@modelcontextprotocol/sdk/-/sdk-1.11.2.tgz#d81784c140d1a9cc937f61af9f071d8b78befe30" + integrity sha512-H9vwztj5OAqHg9GockCQC06k1natgcxWQSRpQcPJf6i5+MWBzfKkRtxGbjQf0X2ihii0ffLZCRGbYV2f2bjNCQ== + dependencies: + content-type "^1.0.5" + cors "^2.8.5" + cross-spawn "^7.0.3" + eventsource "^3.0.2" + express "^5.0.1" + express-rate-limit "^7.5.0" + pkce-challenge "^5.0.0" + raw-body "^3.0.0" + zod "^3.23.8" + zod-to-json-schema "^3.24.1" + +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + 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": + 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== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@pkgr/core@^0.2.3": + version "0.2.4" + resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.2.4.tgz#d897170a2b0ba51f78a099edccd968f7b103387c" + integrity sha512-ROFF39F6ZrnzSUEmQQZUar0Jt4xVoP9WnDRdWwF4NNcXs3xBTLgBUDoOwW141y1jP+S8nahIbdxbFC7IShw9Iw== + +"@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== + +"@sinonjs/commons@^3.0.0": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-3.0.1.tgz#1029357e44ca901a615585f6d27738dbc89084cd" + integrity sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ== + dependencies: + type-detect "4.0.8" + +"@sinonjs/fake-timers@^10.0.2": + version "10.3.0" + resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz#55fdff1ecab9f354019129daf4df0dd4d923ea66" + integrity sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA== + dependencies: + "@sinonjs/commons" "^3.0.0" + +"@ts-morph/common@~0.20.0": + version "0.20.0" + resolved "https://registry.yarnpkg.com/@ts-morph/common/-/common-0.20.0.tgz#3f161996b085ba4519731e4d24c35f6cba5b80af" + integrity sha512-7uKjByfbPpwuzkstL3L5MQyuXPSKdoNG93Fmi2JoDcTf3pEP731JdRFAduRVkOs8oqxPsXKA+ScrWkdQ8t/I+Q== + dependencies: + fast-glob "^3.2.12" + minimatch "^7.4.3" + mkdirp "^2.1.6" + path-browserify "^1.0.1" + +"@tsconfig/node10@^1.0.7": + version "1.0.11" + resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.11.tgz#6ee46400685f130e278128c7b38b7e031ff5b2f2" + integrity sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw== + +"@tsconfig/node12@^1.0.7": + version "1.0.11" + resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.11.tgz#ee3def1f27d9ed66dac6e46a295cffb0152e058d" + integrity sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag== + +"@tsconfig/node14@^1.0.0": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.3.tgz#e4386316284f00b98435bf40f72f75a09dabf6c1" + integrity sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow== + +"@tsconfig/node16@^1.0.2": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.4.tgz#0b92dcc0cc1c81f6f306a381f28e31b1a56536e9" + integrity sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA== + +"@types/babel__core@^7.1.14": + version "7.20.5" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.5.tgz#3df15f27ba85319caa07ba08d0721889bb39c017" + integrity sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA== + dependencies: + "@babel/parser" "^7.20.7" + "@babel/types" "^7.20.7" + "@types/babel__generator" "*" + "@types/babel__template" "*" + "@types/babel__traverse" "*" + +"@types/babel__generator@*": + version "7.27.0" + resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.27.0.tgz#b5819294c51179957afaec341442f9341e4108a9" + integrity sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg== + dependencies: + "@babel/types" "^7.0.0" + +"@types/babel__template@*": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.4.tgz#5672513701c1b2199bc6dad636a9d7491586766f" + integrity sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + +"@types/babel__traverse@*", "@types/babel__traverse@^7.0.6": + version "7.20.7" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.20.7.tgz#968cdc2366ec3da159f61166428ee40f370e56c2" + integrity sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng== + dependencies: + "@babel/types" "^7.20.7" + +"@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" + integrity sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ== + dependencies: + "@types/node" "*" + +"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": + version "2.0.6" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz#7739c232a1fee9b4d3ce8985f314c0c6d33549d7" + integrity sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w== + +"@types/istanbul-lib-report@*": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz#53047614ae72e19fc0401d872de3ae2b4ce350bf" + integrity sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA== + dependencies: + "@types/istanbul-lib-coverage" "*" + +"@types/istanbul-reports@^3.0.0": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz#0f03e3d2f670fbdac586e34b433783070cc16f54" + integrity sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ== + dependencies: + "@types/istanbul-lib-report" "*" + +"@types/jest@^29.4.0": + version "29.5.14" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.14.tgz#2b910912fa1d6856cadcd0c1f95af7df1d6049e5" + integrity sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ== + dependencies: + expect "^29.0.0" + pretty-format "^29.0.0" + +"@types/node@*": + version "22.15.17" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.15.17.tgz#355ccec95f705b664e4332bb64a7f07db30b7055" + integrity sha512-wIX2aSZL5FE+MR0JlvF87BNVrtFWf6AE6rxSE9X7OwnVvoyCQjpzSRJ+M87se/4QCkCiebQAqrJ0y6fwIyi7nw== + dependencies: + undici-types "~6.21.0" + +"@types/stack-utils@^2.0.0": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.3.tgz#6209321eb2c1712a7e7466422b8cb1fc0d9dd5d8" + integrity sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw== + +"@types/yargs-parser@*": + version "21.0.3" + resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.3.tgz#815e30b786d2e8f0dcd85fd5bcf5e1a04d008f15" + integrity sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ== + +"@types/yargs@^17.0.8": + version "17.0.33" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.33.tgz#8c32303da83eec050a84b3c7ae7b9f922d13e32d" + integrity sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA== + dependencies: + "@types/yargs-parser" "*" + +"@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.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.3.1" + natural-compare "^1.4.0" + ts-api-utils "^2.0.1" + +"@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" "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@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" "8.31.1" + "@typescript-eslint/visitor-keys" "8.31.1" + +"@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" "8.31.1" + "@typescript-eslint/utils" "8.31.1" + debug "^4.3.4" + ts-api-utils "^2.0.1" + +"@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@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" "8.31.1" + "@typescript-eslint/visitor-keys" "8.31.1" + debug "^4.3.4" + fast-glob "^3.3.2" + is-glob "^4.0.3" + minimatch "^9.0.4" + semver "^7.6.0" + ts-api-utils "^2.0.1" + +"@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" + "@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": + 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" "8.31.1" + eslint-visitor-keys "^4.2.0" + +"@ungap/structured-clone@^1.2.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.3.0.tgz#d06bbb384ebcf6c505fde1c3d0ed4ddffe0aaff8" + integrity sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g== + +accepts@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-2.0.0.tgz#bbcf4ba5075467f3f2131eab3cffc73c2f5d7895" + integrity sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng== + dependencies: + mime-types "^3.0.0" + negotiator "^1.0.0" + +acorn-jsx@^5.3.2: + version "5.3.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +acorn-walk@^8.1.1: + version "8.3.4" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.4.tgz#794dd169c3977edf4ba4ea47583587c5866236b7" + integrity sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g== + dependencies: + acorn "^8.11.0" + +acorn@^8.11.0, acorn@^8.4.1, acorn@^8.9.0: + version "8.14.1" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.1.tgz#721d5dc10f7d5b5609a891773d47731796935dfb" + integrity sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg== + +aggregate-error@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" + integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== + dependencies: + clean-stack "^2.0.0" + indent-string "^4.0.0" + +ajv@^6.12.4: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ansi-escapes@^4.2.1: + version "4.3.2" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + dependencies: + type-fest "^0.21.3" + +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-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +ansi-styles@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" + integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== + +anymatch@^3.0.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +arg@^4.1.0: + version "4.1.3" + resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" + integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +async@^3.2.3: + version "3.2.6" + resolved "https://registry.yarnpkg.com/async/-/async-3.2.6.tgz#1b0728e14929d51b85b449b7f06e27c1145e38ce" + integrity sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA== + +babel-jest@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.7.0.tgz#f4369919225b684c56085998ac63dbd05be020d5" + integrity sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg== + dependencies: + "@jest/transform" "^29.7.0" + "@types/babel__core" "^7.1.14" + babel-plugin-istanbul "^6.1.1" + babel-preset-jest "^29.6.3" + chalk "^4.0.0" + graceful-fs "^4.2.9" + slash "^3.0.0" + +babel-plugin-istanbul@^6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz#fa88ec59232fd9b4e36dbbc540a8ec9a9b47da73" + integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@istanbuljs/load-nyc-config" "^1.0.0" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-instrument "^5.0.4" + test-exclude "^6.0.0" + +babel-plugin-jest-hoist@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz#aadbe943464182a8922c3c927c3067ff40d24626" + integrity sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg== + dependencies: + "@babel/template" "^7.3.3" + "@babel/types" "^7.3.3" + "@types/babel__core" "^7.1.14" + "@types/babel__traverse" "^7.0.6" + +babel-preset-current-node-syntax@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.1.0.tgz#9a929eafece419612ef4ae4f60b1862ebad8ef30" + integrity sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw== + dependencies: + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-bigint" "^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.10.4" + "@babel/plugin-syntax-nullish-coalescing-operator" "^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-private-property-in-object" "^7.14.5" + "@babel/plugin-syntax-top-level-await" "^7.14.5" + +babel-preset-jest@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz#fa05fa510e7d493896d7b0dd2033601c840f171c" + integrity sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA== + dependencies: + babel-plugin-jest-hoist "^29.6.3" + babel-preset-current-node-syntax "^1.0.0" + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +body-parser@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-2.2.0.tgz#f7a9656de305249a715b549b7b8fd1ab9dfddcfa" + integrity sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg== + dependencies: + bytes "^3.1.2" + content-type "^1.0.5" + debug "^4.4.0" + http-errors "^2.0.0" + iconv-lite "^0.6.3" + on-finished "^2.4.1" + qs "^6.14.0" + raw-body "^3.0.0" + type-is "^2.0.0" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + +braces@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== + dependencies: + fill-range "^7.1.1" + +browserslist@^4.24.0: + version "4.24.5" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.24.5.tgz#aa0f5b8560fe81fde84c6dcb38f759bafba0e11b" + integrity sha512-FDToo4Wo82hIdgc1CQ+NQD0hEhmpPjrZ3hiUgwgOG6IuTdlpr8jdjyG24P6cNP1yJpTLzS5OcGgSw0xmDU1/Tw== + dependencies: + caniuse-lite "^1.0.30001716" + electron-to-chromium "^1.5.149" + node-releases "^2.0.19" + update-browserslist-db "^1.1.3" + +bs-logger@^0.2.6: + version "0.2.6" + resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" + integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog== + dependencies: + fast-json-stable-stringify "2.x" + +bser@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" + integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== + dependencies: + node-int64 "^0.4.0" + +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + +bytes@3.1.2, bytes@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" + integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== + +call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz#4b5428c222be985d79c3d82657479dbe0b59b2d6" + integrity sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ== + dependencies: + es-errors "^1.3.0" + function-bind "^1.1.2" + +call-bound@^1.0.2: + version "1.0.4" + resolved "https://registry.yarnpkg.com/call-bound/-/call-bound-1.0.4.tgz#238de935d2a2a692928c538c7ccfa91067fd062a" + integrity sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg== + dependencies: + call-bind-apply-helpers "^1.0.2" + get-intrinsic "^1.3.0" + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +camelcase@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +camelcase@^6.2.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + +caniuse-lite@^1.0.30001716: + version "1.0.30001717" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001717.tgz#5d9fec5ce09796a1893013825510678928aca129" + integrity sha512-auPpttCq6BDEG8ZAuHJIplGw6GODhjw+/11e7IjpnYCxZcW/ONgPs0KVBJ0d1bY3e2+7PRe5RCLyP+PfwVgkYw== + +chalk@^4.0.0, chalk@^4.0.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +char-regex@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" + integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== + +ci-info@^3.2.0: + version "3.9.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" + integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== + +cjs-module-lexer@^1.0.0: + version "1.4.3" + resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz#0f79731eb8cfe1ec72acd4066efac9d61991b00d" + integrity sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q== + +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== + +cliui@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" + integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.1" + wrap-ansi "^7.0.0" + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ== + +code-block-writer@^12.0.0: + version "12.0.0" + resolved "https://registry.yarnpkg.com/code-block-writer/-/code-block-writer-12.0.0.tgz#4dd58946eb4234105aff7f0035977b2afdc2a770" + integrity sha512-q4dMFMlXtKR3XNBHyMHt/3pwYNA69EDk00lloMOaaUMKPUXBw6lpXtbu3MMVG6/uOihGnRDOlkyqsONEUj60+w== + +collect-v8-coverage@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz#c0b29bcd33bcd0779a1344c2136051e6afd3d9e9" + integrity sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q== + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +content-disposition@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-1.0.0.tgz#844426cb398f934caefcbb172200126bc7ceace2" + integrity sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg== + dependencies: + safe-buffer "5.2.1" + +content-type@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918" + integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA== + +convert-source-map@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" + integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== + +cookie-signature@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.2.2.tgz#57c7fc3cc293acab9fec54d73e15690ebe4a1793" + integrity sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg== + +cookie@^0.7.1: + version "0.7.2" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.7.2.tgz#556369c472a2ba910f2979891b526b3436237ed7" + integrity sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w== + +cors@^2.8.5: + version "2.8.5" + resolved "https://registry.yarnpkg.com/cors/-/cors-2.8.5.tgz#eac11da51592dd86b9f06f6e7ac293b3df875d29" + integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== + dependencies: + object-assign "^4" + vary "^1" + +create-jest@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/create-jest/-/create-jest-29.7.0.tgz#a355c5b3cb1e1af02ba177fe7afd7feee49a5320" + integrity sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q== + dependencies: + "@jest/types" "^29.6.3" + chalk "^4.0.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + jest-config "^29.7.0" + jest-util "^29.7.0" + prompts "^2.0.1" + +create-require@^1.1.0: + version "1.1.1" + 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: + version "7.0.6" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" + integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.5, debug@^4.3.7, debug@^4.4.0: + version "4.4.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a" + integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA== + dependencies: + ms "^2.1.3" + +dedent@^1.0.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.6.0.tgz#79d52d6389b1ffa67d2bcef59ba51847a9d503b2" + integrity sha512-F1Z+5UCFpmQUzJa11agbyPVMbpgT/qA3/SKyJ1jyBgm7dUcUEa8v9JwDkerSQXfakBwFljIxhOJqGkjUwZ9FSA== + +deep-is@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== + +deepmerge@^4.2.2: + version "4.3.1" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" + integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== + +depd@2.0.0, depd@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" + integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== + +detect-newline@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" + integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== + +diff-sequences@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.6.3.tgz#4deaf894d11407c51efc8418012f9e70b84ea921" + integrity sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q== + +diff@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" + integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== + +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" + +dunder-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a" + integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A== + dependencies: + call-bind-apply-helpers "^1.0.1" + es-errors "^1.3.0" + gopd "^1.2.0" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + integrity sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow== + +ejs@^3.1.10: + version "3.1.10" + resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.10.tgz#69ab8358b14e896f80cc39e62087b88500c3ac3b" + integrity sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA== + dependencies: + jake "^10.8.5" + +electron-to-chromium@^1.5.149: + version "1.5.151" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.151.tgz#5edd6c17e1b2f14b4662c41b9379f96cc8c2bb7c" + integrity sha512-Rl6uugut2l9sLojjS4H4SAr3A4IgACMLgpuEMPYCVcKydzfyPrn5absNRju38IhQOf/NwjJY8OGWjlteqYeBCA== + +emittery@^0.13.1: + version "0.13.1" + resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.13.1.tgz#c04b8c3457490e0847ae51fced3af52d338e3dad" + integrity sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +encodeurl@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-2.0.0.tgz#7b8ea898077d7e409d3ac45474ea38eaf0857a58" + integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg== + +error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +es-define-property@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa" + integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g== + +es-errors@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" + integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== + +es-object-atoms@^1.0.0, es-object-atoms@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz#1c4f2c4837327597ce69d2ca190a7fdd172338c1" + integrity sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA== + dependencies: + es-errors "^1.3.0" + +escalade@^3.1.1, escalade@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" + integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== + +escape-html@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow== + +escape-string-regexp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" + integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== + +escape-string-regexp@^4.0.0: + version "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.4.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.4.0.tgz#54d4748904e58eaf1ffe26c4bffa4986ca7f952b" + integrity sha512-BvQOvUhkVQM1i63iMETK9Hjud9QhqBnbtT1Zc642p9ynzBuCe5pybkOnvqZIBypXmMlsGcnU4HZ8sCTPfpAexA== + dependencies: + prettier-linter-helpers "^1.0.0" + synckit "^0.11.0" + +eslint-plugin-unused-imports@^3.0.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-3.2.0.tgz#63a98c9ad5f622cd9f830f70bc77739f25ccfe0d" + integrity sha512-6uXyn6xdINEpxE1MtDjxQsyXB37lfyO2yKGVVgtD7WEWQGORSOZjgrD6hBhvGv4/SO+TOlS+UnC6JppRqbuwGQ== + dependencies: + eslint-rule-composer "^0.3.0" + +eslint-rule-composer@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz#79320c927b0c5c0d3d3d2b76c8b4a488f25bbaf9" + integrity sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg== + +eslint-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== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + +eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: + 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-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@^8.49.0: + version "8.57.1" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.57.1.tgz#7df109654aba7e3bbe5c8eae533c5e461d3c6ca9" + integrity sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.6.1" + "@eslint/eslintrc" "^2.1.4" + "@eslint/js" "8.57.1" + "@humanwhocodes/config-array" "^0.13.0" + "@humanwhocodes/module-importer" "^1.0.1" + "@nodelib/fs.walk" "^1.2.8" + "@ungap/structured-clone" "^1.2.0" + ajv "^6.12.4" + chalk "^4.0.0" + cross-spawn "^7.0.2" + 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" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^6.0.1" + 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== + dependencies: + acorn "^8.9.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^3.4.1" + +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.6.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7" + integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^5.1.0, estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +etag@^1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" + integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== + +eventsource-parser@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/eventsource-parser/-/eventsource-parser-3.0.1.tgz#5e358dba9a55ba64ca90da883c4ca35bd82467bd" + integrity sha512-VARTJ9CYeuQYb0pZEPbzi740OWFgpHe7AYJ2WFZVnUDUQp5Dk2yJUgF36YsZ81cOyxT0QxmXD2EQpapAouzWVA== + +eventsource@^3.0.2: + version "3.0.7" + resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-3.0.7.tgz#1157622e2f5377bb6aef2114372728ba0c156989" + integrity sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA== + dependencies: + eventsource-parser "^3.0.1" + +execa@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== + 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" + +exit@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + integrity sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ== + +expect@^29.0.0, expect@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/expect/-/expect-29.7.0.tgz#578874590dcb3214514084c08115d8aee61e11bc" + integrity sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw== + dependencies: + "@jest/expect-utils" "^29.7.0" + jest-get-type "^29.6.3" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + +express-rate-limit@^7.5.0: + version "7.5.0" + resolved "https://registry.yarnpkg.com/express-rate-limit/-/express-rate-limit-7.5.0.tgz#6a67990a724b4fbbc69119419feef50c51e8b28f" + integrity sha512-eB5zbQh5h+VenMPM3fh+nw1YExi5nMr6HUCR62ELSP11huvxm/Uir1H1QEyTkk5QX6A58pX6NmaTMceKZ0Eodg== + +express@^5.0.1: + version "5.1.0" + resolved "https://registry.yarnpkg.com/express/-/express-5.1.0.tgz#d31beaf715a0016f0d53f47d3b4d7acf28c75cc9" + integrity sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA== + dependencies: + accepts "^2.0.0" + body-parser "^2.2.0" + content-disposition "^1.0.0" + content-type "^1.0.5" + cookie "^0.7.1" + cookie-signature "^1.2.1" + debug "^4.4.0" + encodeurl "^2.0.0" + escape-html "^1.0.3" + etag "^1.8.1" + finalhandler "^2.1.0" + fresh "^2.0.0" + http-errors "^2.0.0" + merge-descriptors "^2.0.0" + mime-types "^3.0.0" + on-finished "^2.4.1" + once "^1.4.0" + parseurl "^1.3.3" + proxy-addr "^2.0.7" + qs "^6.14.0" + range-parser "^1.2.1" + router "^2.2.0" + send "^1.1.0" + serve-static "^2.2.0" + statuses "^2.0.1" + type-is "^2.0.1" + vary "^1.1.2" + +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-diff@^1.1.2: + version "1.3.0" + 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, fast-glob@^3.3.2: + version "3.3.3" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.3.tgz#d06d585ce8dba90a16b0505c543c3ccfb3aeb818" + integrity sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg== + 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.8" + +fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== + +fastq@^1.6.0: + version "1.19.1" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.19.1.tgz#d50eaba803c8846a883c16492821ebcd2cda55f5" + integrity sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ== + dependencies: + reusify "^1.0.4" + +fb-watchman@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.2.tgz#e9524ee6b5c77e9e5001af0f85f3adbb8623255c" + integrity sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA== + dependencies: + bser "2.1.1" + +file-entry-cache@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" + integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== + dependencies: + flat-cache "^3.0.4" + +filelist@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/filelist/-/filelist-1.0.4.tgz#f78978a1e944775ff9e62e744424f215e58352b5" + integrity sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q== + dependencies: + minimatch "^5.0.1" + +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== + dependencies: + to-regex-range "^5.0.1" + +finalhandler@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-2.1.0.tgz#72306373aa89d05a8242ed569ed86a1bff7c561f" + integrity sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q== + dependencies: + debug "^4.4.0" + encodeurl "^2.0.0" + escape-html "^1.0.3" + on-finished "^2.4.1" + parseurl "^1.3.3" + statuses "^2.0.1" + +find-up@^4.0.0, find-up@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +flat-cache@^3.0.4: + version "3.2.0" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.2.0.tgz#2c0c2d5040c99b1632771a9d105725c0115363ee" + integrity sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw== + dependencies: + flatted "^3.2.9" + keyv "^4.5.3" + rimraf "^3.0.2" + +flatted@^3.2.9: + version "3.3.3" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.3.tgz#67c8fad95454a7c7abebf74bb78ee74a44023358" + integrity sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg== + +forwarded@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" + integrity sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow== + +fresh@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-2.0.0.tgz#8dd7df6a1b3a1b3a5cf186c05a5dd267622635a4" + integrity sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A== + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +fsevents@^2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-intrinsic@^1.2.5, get-intrinsic@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01" + integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ== + dependencies: + call-bind-apply-helpers "^1.0.2" + es-define-property "^1.0.1" + es-errors "^1.3.0" + es-object-atoms "^1.1.1" + function-bind "^1.1.2" + get-proto "^1.0.1" + gopd "^1.2.0" + has-symbols "^1.1.0" + hasown "^2.0.2" + math-intrinsics "^1.1.0" + +get-package-type@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" + integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== + +get-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/get-proto/-/get-proto-1.0.1.tgz#150b3f2743869ef3e851ec0c49d15b1d14d00ee1" + integrity sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g== + dependencies: + dunder-proto "^1.0.1" + es-object-atoms "^1.0.0" + +get-stdin@^8.0.0: + version "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: + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + +glob-parent@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob-parent@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + +glob@^7.1.3, glob@^7.1.4: + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.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.24.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.24.0.tgz#8432a19d78ce0c1e833949c36adb345400bb1171" + integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ== + dependencies: + type-fest "^0.20.2" + +gopd@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1" + integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg== + +graceful-fs@^4.2.9: + version "4.2.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + +graphemer@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" + integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +has-symbols@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338" + integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ== + +hasown@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" + integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== + dependencies: + function-bind "^1.1.2" + +html-escaper@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" + integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== + +http-errors@2.0.0, http-errors@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3" + integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ== + dependencies: + depd "2.0.0" + inherits "2.0.4" + setprototypeof "1.2.0" + statuses "2.0.1" + toidentifier "1.0.1" + +human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== + +iconv-lite@0.6.3, iconv-lite@^0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" + integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== + dependencies: + safer-buffer ">= 2.1.2 < 3.0.0" + +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== + +import-fresh@^3.2.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.1.tgz#9cecb56503c0ada1f2741dbbd6546e4b13b57ccf" + integrity sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +import-local@^3.0.2: + version "3.2.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.2.0.tgz#c3d5c745798c02a6f8b897726aba5100186ee260" + integrity sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA== + dependencies: + pkg-dir "^4.2.0" + resolve-cwd "^3.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== + +indent-string@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" + integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.4, inherits@^2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +ipaddr.js@1.9.1: + version "1.9.1" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" + integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== + +is-core-module@^2.16.0: + version "2.16.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.16.1.tgz#2a98801a849f43e2add644fbb6bc6229b19a4ef4" + integrity sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w== + dependencies: + hasown "^2.0.2" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-generator-fn@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" + integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== + +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +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-promise@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-4.0.0.tgz#42ff9f84206c1991d26debf520dd5c01042dd2f3" + integrity sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ== + +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== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz#2d166c4b0644d43a39f04bf6c2edd1e585f31756" + integrity sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg== + +istanbul-lib-instrument@^5.0.4: + version "5.2.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz#d10c8885c2125574e1c231cacadf955675e1ce3d" + integrity sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg== + dependencies: + "@babel/core" "^7.12.3" + "@babel/parser" "^7.14.7" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.2.0" + semver "^6.3.0" + +istanbul-lib-instrument@^6.0.0: + version "6.0.3" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz#fa15401df6c15874bcb2105f773325d78c666765" + integrity sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q== + dependencies: + "@babel/core" "^7.23.9" + "@babel/parser" "^7.23.9" + "@istanbuljs/schema" "^0.1.3" + istanbul-lib-coverage "^3.2.0" + semver "^7.5.4" + +istanbul-lib-report@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz#908305bac9a5bd175ac6a74489eafd0fc2445a7d" + integrity sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw== + dependencies: + istanbul-lib-coverage "^3.0.0" + make-dir "^4.0.0" + supports-color "^7.1.0" + +istanbul-lib-source-maps@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz#895f3a709fcfba34c6de5a42939022f3e4358551" + integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw== + dependencies: + debug "^4.1.1" + istanbul-lib-coverage "^3.0.0" + source-map "^0.6.1" + +istanbul-reports@^3.1.3: + version "3.1.7" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.7.tgz#daed12b9e1dca518e15c056e1e537e741280fa0b" + integrity sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g== + dependencies: + html-escaper "^2.0.0" + istanbul-lib-report "^3.0.0" + +jake@^10.8.5: + version "10.9.2" + resolved "https://registry.yarnpkg.com/jake/-/jake-10.9.2.tgz#6ae487e6a69afec3a5e167628996b59f35ae2b7f" + integrity sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA== + dependencies: + async "^3.2.3" + chalk "^4.0.2" + filelist "^1.0.4" + minimatch "^3.1.2" + +jest-changed-files@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-29.7.0.tgz#1c06d07e77c78e1585d020424dedc10d6e17ac3a" + integrity sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w== + dependencies: + execa "^5.0.0" + jest-util "^29.7.0" + p-limit "^3.1.0" + +jest-circus@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-29.7.0.tgz#b6817a45fcc835d8b16d5962d0c026473ee3668a" + integrity sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/expect" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + dedent "^1.0.0" + is-generator-fn "^2.0.0" + jest-each "^29.7.0" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-runtime "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" + p-limit "^3.1.0" + pretty-format "^29.7.0" + pure-rand "^6.0.0" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-cli@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-29.7.0.tgz#5592c940798e0cae677eec169264f2d839a37995" + integrity sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg== + dependencies: + "@jest/core" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" + chalk "^4.0.0" + create-jest "^29.7.0" + exit "^0.1.2" + import-local "^3.0.2" + jest-config "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" + yargs "^17.3.1" + +jest-config@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-29.7.0.tgz#bcbda8806dbcc01b1e316a46bb74085a84b0245f" + integrity sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ== + dependencies: + "@babel/core" "^7.11.6" + "@jest/test-sequencer" "^29.7.0" + "@jest/types" "^29.6.3" + babel-jest "^29.7.0" + chalk "^4.0.0" + ci-info "^3.2.0" + deepmerge "^4.2.2" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-circus "^29.7.0" + jest-environment-node "^29.7.0" + jest-get-type "^29.6.3" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-runner "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" + micromatch "^4.0.4" + parse-json "^5.2.0" + pretty-format "^29.7.0" + slash "^3.0.0" + strip-json-comments "^3.1.1" + +jest-diff@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.7.0.tgz#017934a66ebb7ecf6f205e84699be10afd70458a" + integrity sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw== + dependencies: + chalk "^4.0.0" + diff-sequences "^29.6.3" + jest-get-type "^29.6.3" + pretty-format "^29.7.0" + +jest-docblock@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-29.7.0.tgz#8fddb6adc3cdc955c93e2a87f61cfd350d5d119a" + integrity sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g== + dependencies: + detect-newline "^3.0.0" + +jest-each@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-29.7.0.tgz#162a9b3f2328bdd991beaabffbb74745e56577d1" + integrity sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ== + dependencies: + "@jest/types" "^29.6.3" + chalk "^4.0.0" + jest-get-type "^29.6.3" + jest-util "^29.7.0" + pretty-format "^29.7.0" + +jest-environment-node@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-29.7.0.tgz#0b93e111dda8ec120bc8300e6d1fb9576e164376" + integrity sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/fake-timers" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + jest-mock "^29.7.0" + jest-util "^29.7.0" + +jest-get-type@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.6.3.tgz#36f499fdcea197c1045a127319c0481723908fd1" + integrity sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw== + +jest-haste-map@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-29.7.0.tgz#3c2396524482f5a0506376e6c858c3bbcc17b104" + integrity sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA== + dependencies: + "@jest/types" "^29.6.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 "^29.6.3" + jest-util "^29.7.0" + jest-worker "^29.7.0" + micromatch "^4.0.4" + walker "^1.0.8" + optionalDependencies: + fsevents "^2.3.2" + +jest-leak-detector@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz#5b7ec0dadfdfec0ca383dc9aa016d36b5ea4c728" + integrity sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw== + dependencies: + jest-get-type "^29.6.3" + pretty-format "^29.7.0" + +jest-matcher-utils@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz#ae8fec79ff249fd592ce80e3ee474e83a6c44f12" + integrity sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g== + dependencies: + chalk "^4.0.0" + jest-diff "^29.7.0" + jest-get-type "^29.6.3" + pretty-format "^29.7.0" + +jest-message-util@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.7.0.tgz#8bc392e204e95dfe7564abbe72a404e28e51f7f3" + integrity sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w== + dependencies: + "@babel/code-frame" "^7.12.13" + "@jest/types" "^29.6.3" + "@types/stack-utils" "^2.0.0" + chalk "^4.0.0" + graceful-fs "^4.2.9" + micromatch "^4.0.4" + pretty-format "^29.7.0" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-mock@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-29.7.0.tgz#4e836cf60e99c6fcfabe9f99d017f3fdd50a6347" + integrity sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw== + dependencies: + "@jest/types" "^29.6.3" + "@types/node" "*" + jest-util "^29.7.0" + +jest-pnp-resolver@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz#930b1546164d4ad5937d5540e711d4d38d4cad2e" + integrity sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w== + +jest-regex-util@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-29.6.3.tgz#4a556d9c776af68e1c5f48194f4d0327d24e8a52" + integrity sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg== + +jest-resolve-dependencies@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz#1b04f2c095f37fc776ff40803dc92921b1e88428" + integrity sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA== + dependencies: + jest-regex-util "^29.6.3" + jest-snapshot "^29.7.0" + +jest-resolve@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-29.7.0.tgz#64d6a8992dd26f635ab0c01e5eef4399c6bcbc30" + integrity sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA== + dependencies: + chalk "^4.0.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + jest-pnp-resolver "^1.2.2" + jest-util "^29.7.0" + jest-validate "^29.7.0" + resolve "^1.20.0" + resolve.exports "^2.0.0" + slash "^3.0.0" + +jest-runner@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-29.7.0.tgz#809af072d408a53dcfd2e849a4c976d3132f718e" + integrity sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ== + dependencies: + "@jest/console" "^29.7.0" + "@jest/environment" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + emittery "^0.13.1" + graceful-fs "^4.2.9" + jest-docblock "^29.7.0" + jest-environment-node "^29.7.0" + jest-haste-map "^29.7.0" + jest-leak-detector "^29.7.0" + jest-message-util "^29.7.0" + jest-resolve "^29.7.0" + jest-runtime "^29.7.0" + jest-util "^29.7.0" + jest-watcher "^29.7.0" + jest-worker "^29.7.0" + p-limit "^3.1.0" + source-map-support "0.5.13" + +jest-runtime@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-29.7.0.tgz#efecb3141cf7d3767a3a0cc8f7c9990587d3d817" + integrity sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/fake-timers" "^29.7.0" + "@jest/globals" "^29.7.0" + "@jest/source-map" "^29.6.3" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + cjs-module-lexer "^1.0.0" + collect-v8-coverage "^1.0.0" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + jest-message-util "^29.7.0" + jest-mock "^29.7.0" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" + slash "^3.0.0" + strip-bom "^4.0.0" + +jest-snapshot@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-29.7.0.tgz#c2c574c3f51865da1bb329036778a69bf88a6be5" + integrity sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw== + dependencies: + "@babel/core" "^7.11.6" + "@babel/generator" "^7.7.2" + "@babel/plugin-syntax-jsx" "^7.7.2" + "@babel/plugin-syntax-typescript" "^7.7.2" + "@babel/types" "^7.3.3" + "@jest/expect-utils" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + babel-preset-current-node-syntax "^1.0.0" + chalk "^4.0.0" + expect "^29.7.0" + graceful-fs "^4.2.9" + jest-diff "^29.7.0" + jest-get-type "^29.6.3" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + natural-compare "^1.4.0" + pretty-format "^29.7.0" + semver "^7.5.3" + +jest-util@^29.0.0, jest-util@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.7.0.tgz#23c2b62bfb22be82b44de98055802ff3710fc0bc" + integrity sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA== + dependencies: + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + ci-info "^3.2.0" + graceful-fs "^4.2.9" + picomatch "^2.2.3" + +jest-validate@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-29.7.0.tgz#7bf705511c64da591d46b15fce41400d52147d9c" + integrity sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw== + dependencies: + "@jest/types" "^29.6.3" + camelcase "^6.2.0" + chalk "^4.0.0" + jest-get-type "^29.6.3" + leven "^3.1.0" + pretty-format "^29.7.0" + +jest-watcher@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-29.7.0.tgz#7810d30d619c3a62093223ce6bb359ca1b28a2f2" + integrity sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g== + dependencies: + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + emittery "^0.13.1" + jest-util "^29.7.0" + string-length "^4.0.1" + +jest-worker@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-29.7.0.tgz#acad073acbbaeb7262bd5389e1bcf43e10058d4a" + integrity sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw== + dependencies: + "@types/node" "*" + jest-util "^29.7.0" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +jest@^29.4.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest/-/jest-29.7.0.tgz#994676fc24177f088f1c5e3737f5697204ff2613" + integrity sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw== + dependencies: + "@jest/core" "^29.7.0" + "@jest/types" "^29.6.3" + import-local "^3.0.2" + jest-cli "^29.7.0" + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^3.13.1: + version "3.14.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" + integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +jsesc@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.1.0.tgz#74d335a234f67ed19907fdadfac7ccf9d409825d" + integrity sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA== + +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" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== + +json5@^2.2.2, json5@^2.2.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" + integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== + +keyv@^4.5.3: + 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" + integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== + +leven@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" + integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== + +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + +lines-and-columns@^1.1.6: + version "1.2.4" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" + integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + +lodash.memoize@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" + integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag== + +lodash.merge@^4.6.2: + version "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@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + +make-dir@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-4.0.0.tgz#c3c2307a771277cd9638305f915c29ae741b614e" + integrity sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw== + dependencies: + semver "^7.5.3" + +make-error@^1.1.1, make-error@^1.3.6: + version "1.3.6" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" + integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== + +makeerror@1.0.12: + version "1.0.12" + resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a" + integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg== + dependencies: + tmpl "1.0.5" + +math-intrinsics@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9" + integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g== + +media-typer@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-1.1.0.tgz#6ab74b8f2d3320f2064b2a87a38e7931ff3a5561" + integrity sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw== + +merge-descriptors@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-2.0.0.tgz#ea922f660635a2249ee565e0449f951e6b603808" + integrity sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g== + +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: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +micromatch@^4.0.4, micromatch@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== + dependencies: + braces "^3.0.3" + picomatch "^2.3.1" + +mime-db@^1.54.0: + version "1.54.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.54.0.tgz#cddb3ee4f9c64530dff640236661d42cb6a314f5" + integrity sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ== + +mime-types@^3.0.0, mime-types@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-3.0.1.tgz#b1d94d6997a9b32fd69ebaed0db73de8acb519ce" + integrity sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA== + dependencies: + mime-db "^1.54.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== + +minimatch@^3.0.4, minimatch@^3.0.5, 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@^7.4.3: + version "7.4.6" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-7.4.6.tgz#845d6f254d8f4a5e4fd6baf44d5f10c8448365fb" + integrity sha512-sBz8G/YjVniEz6lKPNpKxXwazJe4c19fEfV2GDMX6AjFz+MX9uDWIZW8XreVhkFW3fkIdTv/gxWr/Kks5FFAVw== + 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.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== + +mkdirp@^2.1.6: + version "2.1.6" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-2.1.6.tgz#964fbcb12b2d8c5d6fbc62a963ac95a273e2cc19" + integrity sha512-+hEnITedc8LAtIP9u3HJDFIdcLV2vXP33sqLLIzkv1Db1zO/1OxbvYf0Y1OC/S/Qo5dxHXepofhmxL02PsKe+A== + +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== + +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== + +negotiator@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-1.0.0.tgz#b6c91bb47172d69f93cfd7c357bbb529019b5f6a" + integrity sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg== + +node-int64@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== + +node-releases@^2.0.19: + version "2.0.19" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.19.tgz#9e445a52950951ec4d177d843af370b411caf314" + integrity sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw== + +normalize-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +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" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.0.0" + +object-assign@^4: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== + +object-inspect@^1.13.3: + version "1.13.4" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.4.tgz#8375265e21bc20d0fa582c22e1b13485d6e00213" + integrity sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew== + +on-finished@^2.4.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" + integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== + dependencies: + ee-first "1.1.1" + +once@^1.3.0, once@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +onetime@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + +optionator@^0.9.3: + version "0.9.4" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" + integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g== + dependencies: + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + word-wrap "^1.2.5" + +p-all@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-all/-/p-all-3.0.0.tgz#077c023c37e75e760193badab2bad3ccd5782bfb" + integrity sha512-qUZbvbBFVXm6uJ7U/WDiO0fv6waBMbjlCm4E66oZdRR+egswICarIdHyVSZZHudH8T5SF8x/JG0q0duFzPnlBw== + dependencies: + p-map "^4.0.0" + +p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-limit@^3.0.2, p-limit@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + +p-map@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" + integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== + dependencies: + aggregate-error "^3.0.0" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parse-json@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" + integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== + 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" + +parseurl@^1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" + integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== + +path-browserify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-1.0.1.tgz#d98454a9c3753d5790860f16f68867b9e46be1fd" + integrity sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g== + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-key@^3.0.0, path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +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-to-regexp@^8.0.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-8.2.0.tgz#73990cc29e57a3ff2a0d914095156df5db79e8b4" + integrity sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ== + +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" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +pirates@^4.0.4: + version "4.0.7" + resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.7.tgz#643b4a18c4257c8a65104b73f3049ce9a0a15e22" + integrity sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA== + +pkce-challenge@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/pkce-challenge/-/pkce-challenge-5.0.0.tgz#c3a405cb49e272094a38e890a2b51da0228c4d97" + integrity sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ== + +pkg-dir@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + +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" + integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== + dependencies: + fast-diff "^1.1.2" + +prettier@^3.0.0: + version "3.5.3" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.5.3.tgz#4fc2ce0d657e7a02e602549f053b239cb7dfe1b5" + integrity sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw== + +pretty-format@^29.0.0, pretty-format@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.7.0.tgz#ca42c758310f365bfa71a0bda0a807160b776812" + integrity sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ== + dependencies: + "@jest/schemas" "^29.6.3" + ansi-styles "^5.0.0" + react-is "^18.0.0" + +prompts@^2.0.1: + version "2.4.2" + resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" + integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== + dependencies: + kleur "^3.0.3" + sisteransi "^1.0.5" + +proxy-addr@^2.0.7: + version "2.0.7" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.7.tgz#f19fe69ceab311eeb94b42e70e8c2070f9ba1025" + integrity sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg== + dependencies: + forwarded "0.2.0" + ipaddr.js "1.9.1" + +punycode@^2.1.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" + integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== + +pure-rand@^6.0.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-6.1.0.tgz#d173cf23258231976ccbdb05247c9787957604f2" + integrity sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA== + +qs@^6.14.0: + version "6.14.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.14.0.tgz#c63fa40680d2c5c941412a0e899c89af60c0a930" + integrity sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w== + dependencies: + side-channel "^1.1.0" + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +range-parser@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" + integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== + +raw-body@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-3.0.0.tgz#25b3476f07a51600619dae3fe82ddc28a36e5e0f" + integrity sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g== + dependencies: + bytes "3.1.2" + http-errors "2.0.0" + iconv-lite "0.6.3" + unpipe "1.0.0" + +react-is@^18.0.0: + version "18.3.1" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e" + integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg== + +readable-stream@^3.4.0: + version "3.6.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + +resolve-cwd@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" + integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== + dependencies: + resolve-from "^5.0.0" + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + +resolve.exports@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-2.0.3.tgz#41955e6f1b4013b7586f873749a635dea07ebe3f" + integrity sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A== + +resolve@^1.20.0: + version "1.22.10" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.10.tgz#b663e83ffb09bbf2386944736baae803029b8b39" + integrity sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w== + dependencies: + is-core-module "^2.16.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +reusify@^1.0.4: + version "1.1.0" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.1.0.tgz#0fe13b9522e1473f51b558ee796e08f11f9b489f" + integrity sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw== + +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" + +router@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/router/-/router-2.2.0.tgz#019be620b711c87641167cc79b99090f00b146ef" + integrity sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ== + dependencies: + debug "^4.4.0" + depd "^2.0.0" + is-promise "^4.0.0" + parseurl "^1.3.3" + path-to-regexp "^8.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" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +safe-buffer@5.2.1, safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +"safer-buffer@>= 2.1.2 < 3.0.0": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +semver@^6.3.0, semver@^6.3.1: + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + +semver@^7.5.3, semver@^7.5.4, semver@^7.6.0, semver@^7.7.1: + version "7.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.1.tgz#abd5098d82b18c6c81f6074ff2647fd3e7220c9f" + integrity sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA== + +send@^1.1.0, send@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/send/-/send-1.2.0.tgz#32a7554fb777b831dfa828370f773a3808d37212" + integrity sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw== + dependencies: + debug "^4.3.5" + encodeurl "^2.0.0" + escape-html "^1.0.3" + etag "^1.8.1" + fresh "^2.0.0" + http-errors "^2.0.0" + mime-types "^3.0.1" + ms "^2.1.3" + on-finished "^2.4.1" + range-parser "^1.2.1" + statuses "^2.0.1" + +serve-static@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-2.2.0.tgz#9c02564ee259bdd2251b82d659a2e7e1938d66f9" + integrity sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ== + dependencies: + encodeurl "^2.0.0" + escape-html "^1.0.3" + parseurl "^1.3.3" + send "^1.2.0" + +setprototypeof@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" + integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +side-channel-list@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/side-channel-list/-/side-channel-list-1.0.0.tgz#10cb5984263115d3b7a0e336591e290a830af8ad" + integrity sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA== + dependencies: + es-errors "^1.3.0" + object-inspect "^1.13.3" + +side-channel-map@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/side-channel-map/-/side-channel-map-1.0.1.tgz#d6bb6b37902c6fef5174e5f533fab4c732a26f42" + integrity sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + get-intrinsic "^1.2.5" + object-inspect "^1.13.3" + +side-channel-weakmap@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz#11dda19d5368e40ce9ec2bdc1fb0ecbc0790ecea" + integrity sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + get-intrinsic "^1.2.5" + object-inspect "^1.13.3" + side-channel-map "^1.0.1" + +side-channel@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.1.0.tgz#c3fcff9c4da932784873335ec9765fa94ff66bc9" + integrity sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw== + dependencies: + es-errors "^1.3.0" + object-inspect "^1.13.3" + side-channel-list "^1.0.0" + side-channel-map "^1.0.1" + side-channel-weakmap "^1.0.2" + +signal-exit@^3.0.3, signal-exit@^3.0.7: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + +sisteransi@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" + integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +source-map-support@0.5.13: + version "0.5.13" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932" + integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@^0.6.0, source-map@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== + +stack-utils@^2.0.3: + version "2.0.6" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.6.tgz#aaf0748169c02fc33c8232abccf933f54a1cc34f" + integrity sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ== + dependencies: + escape-string-regexp "^2.0.0" + +statuses@2.0.1, statuses@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" + integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ== + +string-length@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" + integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ== + dependencies: + char-regex "^1.0.2" + strip-ansi "^6.0.0" + +string-to-stream@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/string-to-stream/-/string-to-stream-3.0.1.tgz#480e6fb4d5476d31cb2221f75307a5dcb6638a42" + integrity sha512-Hl092MV3USJuUCC6mfl9sPzGloA3K5VwdIeJjYIkXY/8K+mUvaeEabWJgArp+xXrsWxCajeT2pc4axbVhIZJyg== + dependencies: + readable-stream "^3.4.0" + +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== + +strip-bom@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" + integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== + +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + +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.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@^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== + dependencies: + has-flag "^4.0.0" + +supports-color@^8.0.0: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.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.11.0: + version "0.11.4" + resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.11.4.tgz#48972326b59723fc15b8d159803cf8302b545d59" + integrity sha512-Q/XQKRaJiLiFIBNN+mndW7S/RHxvwzuZS6ZwmRzUBqJBv/5QIKCEwkBC8GBf8EQJKYnaFs0wOZbKTXBPj8L9oQ== + dependencies: + "@pkgr/core" "^0.2.3" + tslib "^2.8.1" + +test-exclude@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" + integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== + dependencies: + "@istanbuljs/schema" "^0.1.2" + 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== + +tmpl@1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" + integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +toidentifier@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" + integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== + +ts-api-utils@^2.0.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-2.1.0.tgz#595f7094e46eed364c13fd23e75f9513d29baf91" + integrity sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ== + +ts-jest@^29.1.0: + version "29.3.2" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-29.3.2.tgz#0576cdf0a507f811fe73dcd16d135ce89f8156cb" + integrity sha512-bJJkrWc6PjFVz5g2DGCNUo8z7oFEYaz1xP1NpeDU7KNLMWPpEyV8Chbpkn8xjzgRDpQhnGMyvyldoL7h8JXyug== + dependencies: + bs-logger "^0.2.6" + ejs "^3.1.10" + fast-json-stable-stringify "^2.1.0" + jest-util "^29.0.0" + json5 "^2.2.3" + lodash.memoize "^4.1.2" + make-error "^1.3.6" + semver "^7.7.1" + type-fest "^4.39.1" + yargs-parser "^21.1.1" + +ts-morph@^19.0.0: + version "19.0.0" + resolved "https://registry.yarnpkg.com/ts-morph/-/ts-morph-19.0.0.tgz#43e95fb0156c3fe3c77c814ac26b7d0be2f93169" + integrity sha512-D6qcpiJdn46tUqV45vr5UGM2dnIEuTGNxVhg0sk5NX11orcouwj6i1bMqZIz2mZTZB1Hcgy7C3oEVhAT+f6mbQ== + dependencies: + "@ts-morph/common" "~0.20.0" + code-block-writer "^12.0.0" + +ts-node@^10.5.0: + version "10.9.2" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.9.2.tgz#70f021c9e185bccdca820e26dc413805c101c71f" + 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" + +"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.7" + fast-glob "^3.3.2" + get-stdin "^8.0.0" + p-all "^3.0.0" + picocolors "^1.1.1" + signal-exit "^3.0.7" + string-to-stream "^3.0.1" + superstruct "^1.0.4" + tslib "^2.8.1" + yargs "^17.7.2" + +tsconfig-paths@^4.0.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz#ef78e19039133446d244beac0fd6a1632e2d107c" + integrity sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg== + dependencies: + json5 "^2.2.2" + minimist "^1.2.6" + strip-bom "^3.0.0" + +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" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + +type-detect@4.0.8: + version "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== + +type-fest@^4.39.1: + version "4.41.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-4.41.0.tgz#6ae1c8e5731273c2bf1f58ad39cbae2c91a46c58" + integrity sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA== + +type-is@^2.0.0, type-is@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-2.0.1.tgz#64f6cf03f92fce4015c2b224793f6bdd4b068c97" + integrity sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw== + dependencies: + content-type "^1.0.5" + media-typer "^1.1.0" + mime-types "^3.0.0" + +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@~6.21.0: + version "6.21.0" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.21.0.tgz#691d00af3909be93a7faa13be61b3a5b50ef12cb" + integrity sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ== + +unpipe@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== + +update-browserslist-db@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz#348377dd245216f9e7060ff50b15a1b740b75420" + integrity sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw== + dependencies: + escalade "^3.2.0" + picocolors "^1.1.1" + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +util-deprecate@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + +v8-compile-cache-lib@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz#6336e8d71965cb3d35a1bbb7868445a7c05264bf" + integrity sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg== + +v8-to-istanbul@^9.0.1: + version "9.3.0" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.3.0.tgz#b9572abfa62bd556c16d75fdebc1a411d5ff3175" + integrity sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA== + dependencies: + "@jridgewell/trace-mapping" "^0.3.12" + "@types/istanbul-lib-coverage" "^2.0.1" + convert-source-map "^2.0.0" + +vary@^1, vary@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" + integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== + +walker@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" + integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== + dependencies: + makeerror "1.0.12" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +word-wrap@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" + integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +write-file-atomic@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-4.0.2.tgz#a9df01ae5b77858a027fd2e80768ee433555fcfd" + integrity sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg== + dependencies: + imurmurhash "^0.1.4" + signal-exit "^3.0.7" + +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + +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.2: + version "17.7.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" + integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== + 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" + +yn@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" + integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + +zod-to-json-schema@^3.24.1, zod-to-json-schema@^3.24.5: + version "3.24.5" + resolved "https://registry.yarnpkg.com/zod-to-json-schema/-/zod-to-json-schema-3.24.5.tgz#d1095440b147fb7c2093812a53c54df8d5df50a3" + integrity sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g== + +zod@^3.23.8, zod@^3.24.4: + version "3.24.4" + resolved "https://registry.yarnpkg.com/zod/-/zod-3.24.4.tgz#e2e2cca5faaa012d76e527d0d36622e0a90c315f" + integrity sha512-OdqJE9UDRPwWsrHjLN2F8bPxvwJBK22EHLWtanu0LSYr5YqzsaaW3RMgmjwr8Rypg5k+meEJdSPXJZXE/yqOMg== diff --git a/release-please-config.json b/release-please-config.json index 1ebd0bd..b190980 100644 --- a/release-please-config.json +++ b/release-please-config.json @@ -60,5 +60,14 @@ } ], "release-type": "node", - "extra-files": ["src/version.ts", "README.md"] + "extra-files": [ + "src/version.ts", + "README.md", + "packages/mcp-server/yarn.lock", + { + "type": "json", + "path": "packages/mcp-server/package.json", + "jsonpath": "$.version" + } + ] } diff --git a/scripts/build b/scripts/build index 6fece32..9d3d404 100755 --- a/scripts/build +++ b/scripts/build @@ -51,3 +51,9 @@ if [ -e ./scripts/build-deno ] then ./scripts/build-deno fi +# build all sub-packages +for dir in packages/*; do + if [ -d "$dir" ]; then + (cd "$dir" && yarn install && yarn build) + fi +done diff --git a/scripts/build-all b/scripts/build-all new file mode 100755 index 0000000..4e5ac01 --- /dev/null +++ b/scripts/build-all @@ -0,0 +1,5 @@ +#!/usr/bin/env bash + +# build-all is deprecated, use build instead + +bash ./scripts/build diff --git a/scripts/publish-packages.ts b/scripts/publish-packages.ts new file mode 100644 index 0000000..50e93fe --- /dev/null +++ b/scripts/publish-packages.ts @@ -0,0 +1,102 @@ +/** + * Called from the `create-releases.yml` workflow with the output + * of the release please action as the first argument. + * + * Example JSON input: + * + * ```json + { + "releases_created": "true", + "release_created": "true", + "id": "137967744", + "name": "sdk: v0.14.5", + "tag_name": "sdk-v0.14.5", + "sha": "7cc2ba5c694e76a117f731d4cf0b06f8b8361f2e", + "body": "## 0.14.5 (2024-01-22)\n\n...", + "html_url": "https://github.com/$org/$repo/releases/tag/sdk-v0.14.5", + "draft": "false", + "upload_url": "https://uploads.github.com/repos/$org/$repo/releases/137967744/assets{?name,label}", + "path": ".", + "version": "0.14.5", + "major": "0", + "minor": "14", + "patch": "5", + "packages/additional-sdk--release_created": "true", + "packages/additional-sdk--id": "137967756", + "packages/additional-sdk--name": "additional-sdk: v0.5.2", + "packages/additional-sdk--tag_name": "additional-sdk-v0.5.2", + "packages/additional-sdk--sha": "7cc2ba5c694e76a117f731d4cf0b06f8b8361f2e", + "packages/additional-sdk--body": "## 0.5.2 (2024-01-22)\n\n...", + "packages/additional-sdk--html_url": "https://github.com/$org/$repo/releases/tag/additional-sdk-v0.5.2", + "packages/additional-sdk--draft": "false", + "packages/additional-sdk--upload_url": "https://uploads.github.com/repos/$org/$repo/releases/137967756/assets{?name,label}", + "packages/additional-sdk--path": "packages/additional-sdk", + "packages/additional-sdk--version": "0.5.2", + "packages/additional-sdk--major": "0", + "packages/additional-sdk--minor": "5", + "packages/additional-sdk--patch": "2", + "paths_released": "[\".\",\"packages/additional-sdk\"]" + } + ``` + */ + +import { execSync } from 'child_process'; +import path from 'path'; + +function main() { + const data = process.argv[2] ?? process.env['DATA']; + if (!data) { + throw new Error(`Usage: publish-packages.ts '{"json": "obj"}'`); + } + + const rootDir = path.join(__dirname, '..'); + console.log('root dir', rootDir); + console.log(`publish-packages called with ${data}`); + + const outputs = JSON.parse(data); + + const rawPaths = outputs.paths_released; + + if (!rawPaths) { + console.error(JSON.stringify(outputs, null, 2)); + throw new Error('Expected outputs to contain a truthy `paths_released` property'); + } + if (typeof rawPaths !== 'string') { + console.error(JSON.stringify(outputs, null, 2)); + throw new Error('Expected outputs `paths_released` property to be a JSON string'); + } + + const paths = JSON.parse(rawPaths); + if (!Array.isArray(paths)) { + console.error(JSON.stringify(outputs, null, 2)); + throw new Error('Expected outputs `paths_released` property to be an array'); + } + if (!paths.length) { + console.error(JSON.stringify(outputs, null, 2)); + throw new Error('Expected outputs `paths_released` property to contain at least one entry'); + } + + const publishScriptPath = path.join(rootDir, 'bin', 'publish-npm'); + console.log('Using publish script at', publishScriptPath); + + console.log('Ensuring root package is built'); + console.log(`$ yarn build`); + execSync(`yarn build`, { cwd: rootDir, encoding: 'utf8', stdio: 'inherit' }); + + for (const relPackagePath of paths) { + console.log('\n'); + + const packagePath = path.join(rootDir, relPackagePath); + console.log(`Publishing in directory: ${packagePath}`); + + console.log(`$ yarn install`); + execSync(`yarn install`, { cwd: packagePath, encoding: 'utf8', stdio: 'inherit' }); + + console.log(`$ bash ${publishScriptPath}`); + execSync(`bash ${publishScriptPath}`, { cwd: packagePath, encoding: 'utf8', stdio: 'inherit' }); + } + + console.log('Finished publishing packages'); +} + +main(); diff --git a/scripts/utils/make-dist-package-json.cjs b/scripts/utils/make-dist-package-json.cjs index 7c24f56..4d6634e 100644 --- a/scripts/utils/make-dist-package-json.cjs +++ b/scripts/utils/make-dist-package-json.cjs @@ -12,6 +12,14 @@ processExportMap(pkgJson.exports); for (const key of ['types', 'main', 'module']) { if (typeof pkgJson[key] === 'string') pkgJson[key] = pkgJson[key].replace(/^(\.\/)?dist\//, './'); } +// Fix bin paths if present +if (pkgJson.bin) { + for (const key in pkgJson.bin) { + if (typeof pkgJson.bin[key] === 'string') { + pkgJson.bin[key] = pkgJson.bin[key].replace(/^(\.\/)?dist\//, './'); + } + } +} delete pkgJson.devDependencies; delete pkgJson.scripts.prepack; From affb606757679b71adf86cb4c83a2bffdefbf58c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 21 May 2025 12:30:47 +0000 Subject: [PATCH 07/91] chore(internal): version bump --- .release-please-manifest.json | 2 +- package.json | 2 +- packages/mcp-server/package.json | 2 +- packages/mcp-server/src/server.ts | 2 +- src/version.ts | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index d7a8735..c5e8a3e 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.1.0-alpha.1" + ".": "0.1.0-alpha.2" } diff --git a/package.json b/package.json index b8bbc7b..75d25c3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "scan-documents", - "version": "0.1.0-alpha.1", + "version": "0.1.0-alpha.2", "description": "The official TypeScript library for the Scan Documents API", "author": "Scan Documents <>", "types": "dist/index.d.ts", diff --git a/packages/mcp-server/package.json b/packages/mcp-server/package.json index 4980744..4b43234 100644 --- a/packages/mcp-server/package.json +++ b/packages/mcp-server/package.json @@ -1,6 +1,6 @@ { "name": "scan-documents-mcp", - "version": "0.1.0-alpha.1", + "version": "0.1.0-alpha.2", "description": "The official MCP Server for the Scan Documents API", "author": "Scan Documents <>", "types": "dist/index.d.ts", diff --git a/packages/mcp-server/src/server.ts b/packages/mcp-server/src/server.ts index 30ba904..e4c2142 100644 --- a/packages/mcp-server/src/server.ts +++ b/packages/mcp-server/src/server.ts @@ -19,7 +19,7 @@ export { endpoints } from './tools'; export const server = new McpServer( { name: 'scan_documents_api', - version: '0.1.0-alpha.1', + version: '0.1.0-alpha.2', }, { capabilities: { diff --git a/src/version.ts b/src/version.ts index b0bfd9e..a528f63 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1 +1 @@ -export const VERSION = '0.1.0-alpha.1'; // x-release-please-version +export const VERSION = '0.1.0-alpha.2'; // x-release-please-version From fd3818b26aafb87d6e05c0cd70e6aaab9a5d84bf Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 21 May 2025 12:34:02 +0000 Subject: [PATCH 08/91] codegen metadata --- .stats.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.stats.yml b/.stats.yml index 2efa153..70a473b 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 17 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/scan-documents%2Fscan-documents-04f736d0a9ae5151fec360201288ee49dc02cc4f60adf1ff17c5e3a0bbb639b4.yml openapi_spec_hash: e9d1be2b0eae296e605a9a79af48ab63 -config_hash: 242faa43d2cdcb84a3ac26da983e34c6 +config_hash: 818029fdd668a29182514c788f49e8e1 From adda16f0e5947b722c4272833ca956db15d94767 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 21 May 2025 12:48:33 +0000 Subject: [PATCH 09/91] feat(api): update via SDK Studio --- .stats.yml | 2 +- README.md | 2 +- SECURITY.md | 4 ++++ package.json | 2 +- packages/mcp-server/package.json | 2 +- 5 files changed, 8 insertions(+), 4 deletions(-) diff --git a/.stats.yml b/.stats.yml index 70a473b..27dc012 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 17 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/scan-documents%2Fscan-documents-04f736d0a9ae5151fec360201288ee49dc02cc4f60adf1ff17c5e3a0bbb639b4.yml openapi_spec_hash: e9d1be2b0eae296e605a9a79af48ab63 -config_hash: 818029fdd668a29182514c788f49e8e1 +config_hash: ee078a284af580362c78b746a0c811c2 diff --git a/README.md b/README.md index 9703cec..762d200 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ This library provides convenient access to the Scan Documents REST API from server-side TypeScript or JavaScript. -The full API of this library can be found in [api.md](api.md). +The REST API documentation can be found on [scan-documents.com](https://scan-documents.com/docs). The full API of this library can be found in [api.md](api.md). It is generated with [Stainless](https://www.stainless.com/). diff --git a/SECURITY.md b/SECURITY.md index 0b35be9..cf67981 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -18,6 +18,10 @@ before making any information public. If you encounter security issues that are not directly related to SDKs but pertain to the services or products provided by Scan Documents please follow the respective company's security reporting guidelines. +### Scan Documents Terms and Policies + +Please contact support@scan-documents.com for any questions or concerns regarding security of our services. + --- Thank you for helping us keep the SDKs and systems they interact with secure. diff --git a/package.json b/package.json index 75d25c3..eaeee20 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "scan-documents", "version": "0.1.0-alpha.2", "description": "The official TypeScript library for the Scan Documents API", - "author": "Scan Documents <>", + "author": "Scan Documents ", "types": "dist/index.d.ts", "main": "dist/index.js", "type": "commonjs", diff --git a/packages/mcp-server/package.json b/packages/mcp-server/package.json index 4b43234..604b215 100644 --- a/packages/mcp-server/package.json +++ b/packages/mcp-server/package.json @@ -2,7 +2,7 @@ "name": "scan-documents-mcp", "version": "0.1.0-alpha.2", "description": "The official MCP Server for the Scan Documents API", - "author": "Scan Documents <>", + "author": "Scan Documents ", "types": "dist/index.d.ts", "main": "dist/index.js", "type": "commonjs", From ef65340fb1507f7a3a841951bbd286d1b8a0d703 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 21 May 2025 12:52:32 +0000 Subject: [PATCH 10/91] chore(internal): version bump --- .release-please-manifest.json | 2 +- package.json | 2 +- packages/mcp-server/package.json | 2 +- packages/mcp-server/src/server.ts | 2 +- src/version.ts | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index c5e8a3e..17473a2 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.1.0-alpha.2" + ".": "0.1.0-alpha.3" } diff --git a/package.json b/package.json index eaeee20..b14ca8f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "scan-documents", - "version": "0.1.0-alpha.2", + "version": "0.1.0-alpha.3", "description": "The official TypeScript library for the Scan Documents API", "author": "Scan Documents ", "types": "dist/index.d.ts", diff --git a/packages/mcp-server/package.json b/packages/mcp-server/package.json index 604b215..99523d3 100644 --- a/packages/mcp-server/package.json +++ b/packages/mcp-server/package.json @@ -1,6 +1,6 @@ { "name": "scan-documents-mcp", - "version": "0.1.0-alpha.2", + "version": "0.1.0-alpha.3", "description": "The official MCP Server for the Scan Documents API", "author": "Scan Documents ", "types": "dist/index.d.ts", diff --git a/packages/mcp-server/src/server.ts b/packages/mcp-server/src/server.ts index e4c2142..62a3cf2 100644 --- a/packages/mcp-server/src/server.ts +++ b/packages/mcp-server/src/server.ts @@ -19,7 +19,7 @@ export { endpoints } from './tools'; export const server = new McpServer( { name: 'scan_documents_api', - version: '0.1.0-alpha.2', + version: '0.1.0-alpha.3', }, { capabilities: { diff --git a/src/version.ts b/src/version.ts index a528f63..a64b06c 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1 +1 @@ -export const VERSION = '0.1.0-alpha.2'; // x-release-please-version +export const VERSION = '0.1.0-alpha.3'; // x-release-please-version From 48671e466d6fbd75be10aea990ac8e748868896c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 21 May 2025 19:41:27 +0000 Subject: [PATCH 11/91] feat(api): update via SDK Studio --- .stats.yml | 4 ++-- src/resources/files.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.stats.yml b/.stats.yml index 27dc012..b05f69d 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 17 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/scan-documents%2Fscan-documents-04f736d0a9ae5151fec360201288ee49dc02cc4f60adf1ff17c5e3a0bbb639b4.yml -openapi_spec_hash: e9d1be2b0eae296e605a9a79af48ab63 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/scan-documents%2Fscan-documents-41af66c2f2ba90b745f6c36d89d31281f16d916521b98a8f510ec3a8f90a1efb.yml +openapi_spec_hash: 0c629cd46c640a055b0cfa5d88aad337 config_hash: ee078a284af580362c78b746a0c811c2 diff --git a/src/resources/files.ts b/src/resources/files.ts index f955ef4..95dbcfe 100644 --- a/src/resources/files.ts +++ b/src/resources/files.ts @@ -65,7 +65,7 @@ export class Files extends APIResource { download(id: string, options?: RequestOptions): APIPromise { return this._client.get(path`/v1/files/${id}/download`, { ...options, - headers: buildHeaders([{ Accept: 'image/*' }, options?.headers]), + headers: buildHeaders([{ Accept: 'image/png' }, options?.headers]), __binaryResponse: true, }); } From f6d3b9abe59447408740dab2e64ae70b8c2a6fc3 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 21 May 2025 19:50:32 +0000 Subject: [PATCH 12/91] chore(internal): version bump --- .release-please-manifest.json | 2 +- package.json | 2 +- packages/mcp-server/package.json | 2 +- packages/mcp-server/src/server.ts | 2 +- src/version.ts | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 17473a2..b3b5e58 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.1.0-alpha.3" + ".": "0.1.0-alpha.4" } diff --git a/package.json b/package.json index b14ca8f..ba12075 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "scan-documents", - "version": "0.1.0-alpha.3", + "version": "0.1.0-alpha.4", "description": "The official TypeScript library for the Scan Documents API", "author": "Scan Documents ", "types": "dist/index.d.ts", diff --git a/packages/mcp-server/package.json b/packages/mcp-server/package.json index 99523d3..bd57562 100644 --- a/packages/mcp-server/package.json +++ b/packages/mcp-server/package.json @@ -1,6 +1,6 @@ { "name": "scan-documents-mcp", - "version": "0.1.0-alpha.3", + "version": "0.1.0-alpha.4", "description": "The official MCP Server for the Scan Documents API", "author": "Scan Documents ", "types": "dist/index.d.ts", diff --git a/packages/mcp-server/src/server.ts b/packages/mcp-server/src/server.ts index 62a3cf2..a943e9a 100644 --- a/packages/mcp-server/src/server.ts +++ b/packages/mcp-server/src/server.ts @@ -19,7 +19,7 @@ export { endpoints } from './tools'; export const server = new McpServer( { name: 'scan_documents_api', - version: '0.1.0-alpha.3', + version: '0.1.0-alpha.4', }, { capabilities: { diff --git a/src/version.ts b/src/version.ts index a64b06c..fe6d1df 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1 +1 @@ -export const VERSION = '0.1.0-alpha.3'; // x-release-please-version +export const VERSION = '0.1.0-alpha.4'; // x-release-please-version From 09258cc93e291ee98e8fe00354b6928d251f311d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 21 May 2025 20:03:37 +0000 Subject: [PATCH 13/91] feat(api): update via SDK Studio --- .stats.yml | 4 ++-- src/resources/image-operations.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.stats.yml b/.stats.yml index b05f69d..75146a1 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 17 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/scan-documents%2Fscan-documents-41af66c2f2ba90b745f6c36d89d31281f16d916521b98a8f510ec3a8f90a1efb.yml -openapi_spec_hash: 0c629cd46c640a055b0cfa5d88aad337 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/scan-documents%2Fscan-documents-23ae799fc736c8f97fa04ed405813ed7692c6a9e1ab0d4f9ef90e3de64f3d2f0.yml +openapi_spec_hash: 8af6c6428f6c7b8027e767771c758210 config_hash: ee078a284af580362c78b746a0c811c2 diff --git a/src/resources/image-operations.ts b/src/resources/image-operations.ts index fab8729..349200f 100644 --- a/src/resources/image-operations.ts +++ b/src/resources/image-operations.ts @@ -821,7 +821,7 @@ export namespace ExtractTextRequest { items?: ImageOperationsAPI.JsonSchemaSpec; - properties?: Record; + properties?: unknown; required?: Array; @@ -1412,7 +1412,7 @@ export declare namespace ImageOperationExtractTextParams { items?: ImageOperationsAPI.JsonSchemaSpec; - properties?: Record; + properties?: unknown; required?: Array; From 90c2e6f8df4778012bb691f0a90183288db71cdd Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 21 May 2025 20:04:27 +0000 Subject: [PATCH 14/91] feat(api): update via SDK Studio --- .stats.yml | 4 ++-- src/resources/image-operations.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.stats.yml b/.stats.yml index 75146a1..b05f69d 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 17 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/scan-documents%2Fscan-documents-23ae799fc736c8f97fa04ed405813ed7692c6a9e1ab0d4f9ef90e3de64f3d2f0.yml -openapi_spec_hash: 8af6c6428f6c7b8027e767771c758210 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/scan-documents%2Fscan-documents-41af66c2f2ba90b745f6c36d89d31281f16d916521b98a8f510ec3a8f90a1efb.yml +openapi_spec_hash: 0c629cd46c640a055b0cfa5d88aad337 config_hash: ee078a284af580362c78b746a0c811c2 diff --git a/src/resources/image-operations.ts b/src/resources/image-operations.ts index 349200f..fab8729 100644 --- a/src/resources/image-operations.ts +++ b/src/resources/image-operations.ts @@ -821,7 +821,7 @@ export namespace ExtractTextRequest { items?: ImageOperationsAPI.JsonSchemaSpec; - properties?: unknown; + properties?: Record; required?: Array; @@ -1412,7 +1412,7 @@ export declare namespace ImageOperationExtractTextParams { items?: ImageOperationsAPI.JsonSchemaSpec; - properties?: unknown; + properties?: Record; required?: Array; From b0950b07328d4b3ab7a500e1c977bc902e1a6d78 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 22 May 2025 02:24:22 +0000 Subject: [PATCH 15/91] chore(docs): grammar improvements --- SECURITY.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index cf67981..fb762fc 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -16,11 +16,11 @@ before making any information public. ## Reporting Non-SDK Related Security Issues If you encounter security issues that are not directly related to SDKs but pertain to the services -or products provided by Scan Documents please follow the respective company's security reporting guidelines. +or products provided by Scan Documents, please follow the respective company's security reporting guidelines. ### Scan Documents Terms and Policies -Please contact support@scan-documents.com for any questions or concerns regarding security of our services. +Please contact support@scan-documents.com for any questions or concerns regarding the security of our services. --- From d7b66e62665ef166bc74f51b8e98237c7ba7f2b3 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 22 May 2025 12:12:22 +0000 Subject: [PATCH 16/91] feat(api): update via SDK Studio --- .stats.yml | 6 ++-- api.md | 1 - .../extract-text-image-operations.ts | 35 +------------------ src/client.ts | 2 -- src/resources/image-operations.ts | 27 +++----------- src/resources/index.ts | 1 - 6 files changed, 8 insertions(+), 64 deletions(-) diff --git a/.stats.yml b/.stats.yml index b05f69d..be8454c 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 17 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/scan-documents%2Fscan-documents-41af66c2f2ba90b745f6c36d89d31281f16d916521b98a8f510ec3a8f90a1efb.yml -openapi_spec_hash: 0c629cd46c640a055b0cfa5d88aad337 -config_hash: ee078a284af580362c78b746a0c811c2 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/scan-documents%2Fscan-documents-89170108a4ff25a4120f8723c8c03382b8cc176008e091b90ec26fbd3613b199.yml +openapi_spec_hash: a627d69beb662fa6e8bd9c0ace7bf243 +config_hash: c0982818f8942bd915b5e0d65b61be67 diff --git a/api.md b/api.md index 884d588..ea8198c 100644 --- a/api.md +++ b/api.md @@ -48,7 +48,6 @@ Types: - ExtractTextRequest - ExtractTextResponse - ImageFromTaskResponse -- JsonSchemaSpec - WarpRequest - WarpResponse diff --git a/packages/mcp-server/src/tools/image-operations/extract-text-image-operations.ts b/packages/mcp-server/src/tools/image-operations/extract-text-image-operations.ts index 3c13c7f..974c2ac 100644 --- a/packages/mcp-server/src/tools/image-operations/extract-text-image-operations.ts +++ b/packages/mcp-server/src/tools/image-operations/extract-text-image-operations.ts @@ -85,7 +85,7 @@ export const tool: Tool = { type: 'string', }, items: { - $ref: '#/$defs/json_schema_spec', + type: 'object', }, properties: { type: 'object', @@ -106,39 +106,6 @@ export const tool: Tool = { }, }, ], - $defs: { - json_schema_spec: { - type: 'object', - properties: { - description: { - type: 'string', - }, - example: { - type: 'object', - }, - format: { - type: 'string', - }, - items: { - $ref: '#/$defs/json_schema_spec', - }, - properties: { - type: 'object', - }, - required: { - type: 'array', - items: { - type: 'string', - }, - }, - type: { - type: 'string', - enum: ['string', 'number', 'integer', 'boolean', 'array', 'object'], - }, - }, - required: [], - }, - }, }, }; diff --git a/src/client.ts b/src/client.ts index b47256b..4d65f4b 100644 --- a/src/client.ts +++ b/src/client.ts @@ -38,7 +38,6 @@ import { ImageOperationExtractTextParams, ImageOperationWarpParams, ImageOperations, - JsonSchemaSpec, WarpRequest, WarpResponse, } from './resources/image-operations'; @@ -771,7 +770,6 @@ export declare namespace ScanDocuments { type ExtractTextRequest as ExtractTextRequest, type ExtractTextResponse as ExtractTextResponse, type ImageFromTaskResponse as ImageFromTaskResponse, - type JsonSchemaSpec as JsonSchemaSpec, type WarpRequest as WarpRequest, type WarpResponse as WarpResponse, type ImageOperationApplyEffectParams as ImageOperationApplyEffectParams, diff --git a/src/resources/image-operations.ts b/src/resources/image-operations.ts index fab8729..c69ce28 100644 --- a/src/resources/image-operations.ts +++ b/src/resources/image-operations.ts @@ -819,9 +819,9 @@ export namespace ExtractTextRequest { format?: string; - items?: ImageOperationsAPI.JsonSchemaSpec; + items?: unknown; - properties?: Record; + properties?: Record; required?: Array; @@ -1046,24 +1046,6 @@ export namespace ImageFromTaskResponse { } } -export interface JsonSchemaSpec { - description?: string; - - example?: unknown; - - format?: string; - - items?: JsonSchemaSpec; - - properties?: Record; - - required?: Array; - - type?: 'string' | 'number' | 'integer' | 'boolean' | 'array' | 'object'; - - [k: string]: unknown; -} - /** * Transform an image by warping it to a quadrilateral. */ @@ -1410,9 +1392,9 @@ export declare namespace ImageOperationExtractTextParams { format?: string; - items?: ImageOperationsAPI.JsonSchemaSpec; + items?: unknown; - properties?: Record; + properties?: Record; required?: Array; @@ -1451,7 +1433,6 @@ export declare namespace ImageOperations { type ExtractTextRequest as ExtractTextRequest, type ExtractTextResponse as ExtractTextResponse, type ImageFromTaskResponse as ImageFromTaskResponse, - type JsonSchemaSpec as JsonSchemaSpec, type WarpRequest as WarpRequest, type WarpResponse as WarpResponse, type ImageOperationApplyEffectParams as ImageOperationApplyEffectParams, diff --git a/src/resources/index.ts b/src/resources/index.ts index 2d6e2ff..fd22245 100644 --- a/src/resources/index.ts +++ b/src/resources/index.ts @@ -13,7 +13,6 @@ export { type ExtractTextRequest, type ExtractTextResponse, type ImageFromTaskResponse, - type JsonSchemaSpec, type WarpRequest, type WarpResponse, type ImageOperationApplyEffectParams, From 3e97c7ae7a0561ddc266564b29dd8e6e02bd1162 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 22 May 2025 12:15:28 +0000 Subject: [PATCH 17/91] feat(api): update via SDK Studio --- .stats.yml | 2 +- api.md | 6 ++ .../extract-text-image-operations.ts | 65 ++++++++++--------- src/client.ts | 2 + src/resources/image-operations.ts | 53 +-------------- src/resources/index.ts | 1 + src/resources/shared.ts | 27 ++++++++ 7 files changed, 75 insertions(+), 81 deletions(-) create mode 100644 src/resources/shared.ts diff --git a/.stats.yml b/.stats.yml index be8454c..d65b4ff 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 17 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/scan-documents%2Fscan-documents-89170108a4ff25a4120f8723c8c03382b8cc176008e091b90ec26fbd3613b199.yml openapi_spec_hash: a627d69beb662fa6e8bd9c0ace7bf243 -config_hash: c0982818f8942bd915b5e0d65b61be67 +config_hash: 4f1180f734cbc7323ff2ed85a9cd510d diff --git a/api.md b/api.md index ea8198c..1984514 100644 --- a/api.md +++ b/api.md @@ -1,3 +1,9 @@ +# Shared + +Types: + +- JsonSchemaSpec + # Files Types: diff --git a/packages/mcp-server/src/tools/image-operations/extract-text-image-operations.ts b/packages/mcp-server/src/tools/image-operations/extract-text-image-operations.ts index 974c2ac..0bed11f 100644 --- a/packages/mcp-server/src/tools/image-operations/extract-text-image-operations.ts +++ b/packages/mcp-server/src/tools/image-operations/extract-text-image-operations.ts @@ -71,41 +71,46 @@ export const tool: Tool = { description: 'The id of the file to operate on.', }, schema: { + $ref: '#/$defs/json_schema_spec', + }, + }, + }, + ], + $defs: { + json_schema_spec: { + type: 'object', + description: + "An OpenAPI schema object describing the expected JSON structure. Required if format is 'json'.", + properties: { + description: { + type: 'string', + }, + example: { + type: 'object', + }, + format: { + type: 'string', + }, + items: { + $ref: '#/$defs/json_schema_spec', + }, + properties: { type: 'object', - description: - "An OpenAPI schema object describing the expected JSON structure. Required if format is 'json'.", - properties: { - description: { - type: 'string', - }, - example: { - type: 'object', - }, - format: { - type: 'string', - }, - items: { - type: 'object', - }, - properties: { - type: 'object', - }, - required: { - type: 'array', - items: { - type: 'string', - }, - }, - type: { - type: 'string', - enum: ['string', 'number', 'integer', 'boolean', 'array', 'object'], - }, + }, + required: { + type: 'array', + items: { + type: 'string', }, - required: [], + }, + type: { + type: 'string', + enum: ['string', 'number', 'integer', 'boolean', 'array', 'object'], }, }, + required: [], }, - ], + }, }, }; diff --git a/src/client.ts b/src/client.ts index 4d65f4b..80bfe52 100644 --- a/src/client.ts +++ b/src/client.ts @@ -791,4 +791,6 @@ export declare namespace ScanDocuments { type PdfOperationRenderParams as PdfOperationRenderParams, type PdfOperationSplitParams as PdfOperationSplitParams, }; + + export type JsonSchemaSpec = API.JsonSchemaSpec; } diff --git a/src/resources/image-operations.ts b/src/resources/image-operations.ts index c69ce28..5f1345f 100644 --- a/src/resources/image-operations.ts +++ b/src/resources/image-operations.ts @@ -2,6 +2,7 @@ import { APIResource } from '../core/resource'; import * as ImageOperationsAPI from './image-operations'; +import * as Shared from './shared'; import { APIPromise } from '../core/api-promise'; import { RequestOptions } from '../internal/request-options'; @@ -804,31 +805,7 @@ export namespace ExtractTextRequest { * An OpenAPI schema object describing the expected JSON structure. Required if * format is 'json'. */ - schema: Json.Schema; - } - - export namespace Json { - /** - * An OpenAPI schema object describing the expected JSON structure. Required if - * format is 'json'. - */ - export interface Schema { - description?: string; - - example?: unknown; - - format?: string; - - items?: unknown; - - properties?: Record; - - required?: Array; - - type?: 'string' | 'number' | 'integer' | 'boolean' | 'array' | 'object'; - - [k: string]: unknown; - } + schema: Shared.JsonSchemaSpec; } } @@ -1377,31 +1354,7 @@ export declare namespace ImageOperationExtractTextParams { * An OpenAPI schema object describing the expected JSON structure. Required if * format is 'json'. */ - schema: Json.Schema; - } - - export namespace Json { - /** - * An OpenAPI schema object describing the expected JSON structure. Required if - * format is 'json'. - */ - export interface Schema { - description?: string; - - example?: unknown; - - format?: string; - - items?: unknown; - - properties?: Record; - - required?: Array; - - type?: 'string' | 'number' | 'integer' | 'boolean' | 'array' | 'object'; - - [k: string]: unknown; - } + schema: Shared.JsonSchemaSpec; } } diff --git a/src/resources/index.ts b/src/resources/index.ts index fd22245..d5e18da 100644 --- a/src/resources/index.ts +++ b/src/resources/index.ts @@ -1,5 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +export * from './shared'; export { Events, type EventListResponse, type EventListParams } from './events'; export { Files, type File, type FileListResponse, type FileListParams, type FileUploadParams } from './files'; export { diff --git a/src/resources/shared.ts b/src/resources/shared.ts new file mode 100644 index 0000000..a38034f --- /dev/null +++ b/src/resources/shared.ts @@ -0,0 +1,27 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +/** + * An OpenAPI schema object describing the expected JSON structure. Required if + * format is 'json'. + */ +export interface JsonSchemaSpec { + description?: string; + + example?: unknown; + + format?: string; + + /** + * An OpenAPI schema object describing the expected JSON structure. Required if + * format is 'json'. + */ + items?: JsonSchemaSpec; + + properties?: Record; + + required?: Array; + + type?: 'string' | 'number' | 'integer' | 'boolean' | 'array' | 'object'; + + [k: string]: unknown; +} From 8dc630707590054f366f3f7cefe3286c6db03b48 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 23 May 2025 04:07:04 +0000 Subject: [PATCH 18/91] chore(internal): codegen related update --- packages/mcp-server/yarn.lock | 162 ++++++++++++++++++++++++++++++++-- 1 file changed, 156 insertions(+), 6 deletions(-) diff --git a/packages/mcp-server/yarn.lock b/packages/mcp-server/yarn.lock index 9056173..0868204 100644 --- a/packages/mcp-server/yarn.lock +++ b/packages/mcp-server/yarn.lock @@ -585,9 +585,9 @@ "@jridgewell/sourcemap-codec" "^1.4.14" "@modelcontextprotocol/sdk@^1.6.1": - version "1.11.2" - resolved "https://registry.yarnpkg.com/@modelcontextprotocol/sdk/-/sdk-1.11.2.tgz#d81784c140d1a9cc937f61af9f071d8b78befe30" - integrity sha512-H9vwztj5OAqHg9GockCQC06k1natgcxWQSRpQcPJf6i5+MWBzfKkRtxGbjQf0X2ihii0ffLZCRGbYV2f2bjNCQ== + version "1.11.1" + resolved "https://registry.yarnpkg.com/@modelcontextprotocol/sdk/-/sdk-1.11.1.tgz#c7f4a1432872ef10130f5d9b0072060c17a3946b" + integrity sha512-9LfmxKTb1v+vUS1/emSk1f5ePmTLkb9Le9AxOB5T0XM59EUumwcS45z05h7aiZx3GI0Bl7mjb3FMEglYj+acuQ== dependencies: content-type "^1.0.5" cors "^2.8.5" @@ -742,6 +742,14 @@ expect "^29.0.0" pretty-format "^29.0.0" +"@types/node-fetch@^2.6.4": + version "2.6.12" + resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.12.tgz#8ab5c3ef8330f13100a7479e2cd56d3386830a03" + integrity sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA== + dependencies: + "@types/node" "*" + form-data "^4.0.0" + "@types/node@*": version "22.15.17" resolved "https://registry.yarnpkg.com/@types/node/-/node-22.15.17.tgz#355ccec95f705b664e4332bb64a7f07db30b7055" @@ -749,6 +757,13 @@ dependencies: undici-types "~6.21.0" +"@types/node@^18.11.18": + version "18.19.100" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.19.100.tgz#7f3aefbb6911099ab7e0902a1f373b1a4d2c1947" + integrity sha512-ojmMP8SZBKprc3qGrGk8Ujpo80AXkrP7G2tOT4VWr5jlr5DHjsJF+emXJz+Wm0glmy4Js62oKMdZZ6B9Y+tEcA== + dependencies: + undici-types "~5.26.4" + "@types/stack-utils@^2.0.0": version "2.0.3" resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.3.tgz#6209321eb2c1712a7e7466422b8cb1fc0d9dd5d8" @@ -852,6 +867,13 @@ resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.3.0.tgz#d06bbb384ebcf6c505fde1c3d0ed4ddffe0aaff8" integrity sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g== +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" + accepts@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/accepts/-/accepts-2.0.0.tgz#bbcf4ba5075467f3f2131eab3cffc73c2f5d7895" @@ -877,6 +899,13 @@ acorn@^8.11.0, acorn@^8.4.1, acorn@^8.9.0: resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.1.tgz#721d5dc10f7d5b5609a891773d47731796935dfb" integrity sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg== +agentkeepalive@^4.2.1: + version "4.6.0" + resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.6.0.tgz#35f73e94b3f40bf65f105219c623ad19c136ea6a" + integrity sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ== + dependencies: + 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" @@ -949,6 +978,11 @@ async@^3.2.3: resolved "https://registry.yarnpkg.com/async/-/async-3.2.6.tgz#1b0728e14929d51b85b449b7f06e27c1145e38ce" integrity sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA== +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + babel-jest@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.7.0.tgz#f4369919225b684c56085998ac63dbd05be020d5" @@ -1188,6 +1222,13 @@ 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" + concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" @@ -1277,6 +1318,11 @@ 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== +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + depd@2.0.0, depd@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" @@ -1369,6 +1415,16 @@ es-object-atoms@^1.0.0, es-object-atoms@^1.1.1: dependencies: es-errors "^1.3.0" +es-set-tostringtag@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz#f31dbbe0c183b00a6d26eb6325c810c0fd18bd4d" + integrity sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA== + dependencies: + es-errors "^1.3.0" + get-intrinsic "^1.2.6" + has-tostringtag "^1.0.2" + hasown "^2.0.2" + escalade@^3.1.1, escalade@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" @@ -1514,6 +1570,11 @@ etag@^1.8.1: resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== +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== + eventsource-parser@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/eventsource-parser/-/eventsource-parser-3.0.1.tgz#5e358dba9a55ba64ca90da883c4ca35bd82467bd" @@ -1703,6 +1764,29 @@ flatted@^3.2.9: resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.3.tgz#67c8fad95454a7c7abebf74bb78ee74a44023358" integrity sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg== +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@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.2.tgz#35cabbdd30c3ce73deb2c42d3c8d3ed9ca51794c" + integrity sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + es-set-tostringtag "^2.1.0" + mime-types "^2.1.12" + +formdata-node@^4.3.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/formdata-node/-/formdata-node-4.4.1.tgz#23f6a5cb9cb55315912cbec4ff7b0f59bbd191e2" + integrity sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ== + dependencies: + node-domexception "1.0.0" + web-streams-polyfill "4.0.0-beta.3" + forwarded@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" @@ -1738,7 +1822,7 @@ get-caller-file@^2.0.5: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== -get-intrinsic@^1.2.5, get-intrinsic@^1.3.0: +get-intrinsic@^1.2.5, get-intrinsic@^1.2.6, get-intrinsic@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01" integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ== @@ -1835,11 +1919,18 @@ has-flag@^4.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== -has-symbols@^1.1.0: +has-symbols@^1.0.3, has-symbols@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338" integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ== +has-tostringtag@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" + integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== + dependencies: + has-symbols "^1.0.3" + hasown@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" @@ -1868,6 +1959,13 @@ 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== +humanize-ms@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" + integrity sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ== + dependencies: + ms "^2.0.0" + iconv-lite@0.6.3, iconv-lite@^0.6.3: version "0.6.3" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" @@ -2567,11 +2665,23 @@ micromatch@^4.0.4, micromatch@^4.0.8: braces "^3.0.3" picomatch "^2.3.1" +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + mime-db@^1.54.0: version "1.54.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.54.0.tgz#cddb3ee4f9c64530dff640236661d42cb6a314f5" integrity sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ== +mime-types@^2.1.12: + version "2.1.35" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + mime-types@^3.0.0, mime-types@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-3.0.1.tgz#b1d94d6997a9b32fd69ebaed0db73de8acb519ce" @@ -2622,7 +2732,7 @@ mkdirp@^2.1.6: resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-2.1.6.tgz#964fbcb12b2d8c5d6fbc62a963ac95a273e2cc19" integrity sha512-+hEnITedc8LAtIP9u3HJDFIdcLV2vXP33sqLLIzkv1Db1zO/1OxbvYf0Y1OC/S/Qo5dxHXepofhmxL02PsKe+A== -ms@^2.1.3: +ms@^2.0.0, 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== @@ -2637,6 +2747,18 @@ negotiator@^1.0.0: resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-1.0.0.tgz#b6c91bb47172d69f93cfd7c357bbb529019b5f6a" integrity sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg== +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.7.0" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" + integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== + dependencies: + whatwg-url "^5.0.0" + node-int64@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" @@ -3257,6 +3379,11 @@ toidentifier@1.0.1: resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== + ts-api-utils@^2.0.1: version "2.1.0" resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-2.1.0.tgz#595f7094e46eed364c13fd23e75f9513d29baf91" @@ -3375,6 +3502,11 @@ typescript@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== + undici-types@~6.21.0: version "6.21.0" resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.21.0.tgz#691d00af3909be93a7faa13be61b3a5b50ef12cb" @@ -3431,6 +3563,24 @@ walker@^1.0.8: dependencies: makeerror "1.0.12" +web-streams-polyfill@4.0.0-beta.3: + version "4.0.0-beta.3" + resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz#2898486b74f5156095e473efe989dcf185047a38" + integrity sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug== + +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== + +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== + 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" From cb6b1daf725e9901601fa392f10e9e52de59c435 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 24 May 2025 03:22:24 +0000 Subject: [PATCH 19/91] fix(mcp): fix cursor schema transformation issue with recursive references --- packages/mcp-server/src/compat.ts | 17 +++- packages/mcp-server/tests/compat.test.ts | 98 ++++++++++++++++++++++++ 2 files changed, 111 insertions(+), 4 deletions(-) diff --git a/packages/mcp-server/src/compat.ts b/packages/mcp-server/src/compat.ts index e4d48a4..2cf24a0 100644 --- a/packages/mcp-server/src/compat.ts +++ b/packages/mcp-server/src/compat.ts @@ -148,7 +148,11 @@ export function removeTopLevelUnions(tool: Tool): Tool[] { }); } -function findUsedDefs(schema: JSONSchema, defs: Record): Record { +function findUsedDefs( + schema: JSONSchema, + defs: Record, + visited: Set = new Set(), +): Record { const usedDefs: Record = {}; if (typeof schema !== 'object' || schema === null) { @@ -160,9 +164,11 @@ function findUsedDefs(schema: JSONSchema, defs: Record): Rec if (refParts[0] === '#' && refParts[1] === '$defs' && refParts[2]) { const defName = refParts[2]; const def = defs[defName]; - if (def) { + if (def && !visited.has(schema.$ref)) { usedDefs[defName] = def; - Object.assign(usedDefs, findUsedDefs(def, defs)); + visited.add(schema.$ref); + Object.assign(usedDefs, findUsedDefs(def, defs, visited)); + visited.delete(schema.$ref); } } return usedDefs; @@ -170,13 +176,16 @@ function findUsedDefs(schema: JSONSchema, defs: Record): Rec for (const key in schema) { if (key !== '$defs' && typeof schema[key] === 'object' && schema[key] !== null) { - Object.assign(usedDefs, findUsedDefs(schema[key] as JSONSchema, defs)); + Object.assign(usedDefs, findUsedDefs(schema[key] as JSONSchema, defs, visited)); } } return usedDefs; } +// Export for testing +export { findUsedDefs }; + /** * Inlines all $refs in a schema, eliminating $defs. * If a circular reference is detected, the circular property is removed. diff --git a/packages/mcp-server/tests/compat.test.ts b/packages/mcp-server/tests/compat.test.ts index 034b35c..d6272f6 100644 --- a/packages/mcp-server/tests/compat.test.ts +++ b/packages/mcp-server/tests/compat.test.ts @@ -5,6 +5,7 @@ import { inlineRefs, applyCompatibilityTransformations, removeFormats, + findUsedDefs, } from '../src/compat'; import { Tool } from '@modelcontextprotocol/sdk/types.js'; import { JSONSchema } from '../src/compat'; @@ -316,6 +317,103 @@ describe('removeAnyOf', () => { }); }); +describe('findUsedDefs', () => { + it('should handle circular references without stack overflow', () => { + const defs = { + person: { + type: 'object', + properties: { + name: { type: 'string' }, + friend: { $ref: '#/$defs/person' }, // Circular reference + }, + }, + }; + + const schema = { + type: 'object', + properties: { + user: { $ref: '#/$defs/person' }, + }, + }; + + // This should not throw a stack overflow error + expect(() => { + const result = findUsedDefs(schema, defs); + expect(result).toHaveProperty('person'); + }).not.toThrow(); + }); + + it('should handle indirect circular references without stack overflow', () => { + const defs = { + node: { + type: 'object', + properties: { + value: { type: 'string' }, + child: { $ref: '#/$defs/childNode' }, + }, + }, + childNode: { + type: 'object', + properties: { + value: { type: 'string' }, + parent: { $ref: '#/$defs/node' }, // Indirect circular reference + }, + }, + }; + + const schema = { + type: 'object', + properties: { + root: { $ref: '#/$defs/node' }, + }, + }; + + // This should not throw a stack overflow error + expect(() => { + const result = findUsedDefs(schema, defs); + expect(result).toHaveProperty('node'); + expect(result).toHaveProperty('childNode'); + }).not.toThrow(); + }); + + it('should find all used definitions in non-circular schemas', () => { + const defs = { + user: { + type: 'object', + properties: { + name: { type: 'string' }, + address: { $ref: '#/$defs/address' }, + }, + }, + address: { + type: 'object', + properties: { + street: { type: 'string' }, + city: { type: 'string' }, + }, + }, + unused: { + type: 'object', + properties: { + data: { type: 'string' }, + }, + }, + }; + + const schema = { + type: 'object', + properties: { + person: { $ref: '#/$defs/user' }, + }, + }; + + const result = findUsedDefs(schema, defs); + expect(result).toHaveProperty('user'); + expect(result).toHaveProperty('address'); + expect(result).not.toHaveProperty('unused'); + }); +}); + describe('inlineRefs', () => { it('should return the original schema if it does not contain $refs', () => { const schema: JSONSchema = { From 02f4f1841802db42f723763608e3865ff6ba72d7 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 28 May 2025 02:13:57 +0000 Subject: [PATCH 20/91] fix(mcp): include description in dynamic tool search --- packages/mcp-server/src/dynamic-tools.ts | 3 +- .../mcp-server/tests/dynamic-tools.test.ts | 91 ++++++++++--------- 2 files changed, 50 insertions(+), 44 deletions(-) diff --git a/packages/mcp-server/src/dynamic-tools.ts b/packages/mcp-server/src/dynamic-tools.ts index b15efd3..d184ee8 100644 --- a/packages/mcp-server/src/dynamic-tools.ts +++ b/packages/mcp-server/src/dynamic-tools.ts @@ -49,11 +49,12 @@ export function dynamicTools(endpoints: Endpoint[]): Endpoint[] { endpoints.filter((endpoint) => { const fieldsToMatch = [ endpoint.tool.name, + endpoint.tool.description, endpoint.metadata.resource, endpoint.metadata.operation, ...endpoint.metadata.tags, ]; - return fieldsToMatch.some((field) => field.toLowerCase().includes(query.toLowerCase())); + return fieldsToMatch.some((field) => field && field.toLowerCase().includes(query.toLowerCase())); }) : endpoints; diff --git a/packages/mcp-server/tests/dynamic-tools.test.ts b/packages/mcp-server/tests/dynamic-tools.test.ts index c74ef4a..e2da6bd 100644 --- a/packages/mcp-server/tests/dynamic-tools.test.ts +++ b/packages/mcp-server/tests/dynamic-tools.test.ts @@ -13,13 +13,15 @@ describe('dynamicTools', () => { const tools = dynamicTools(endpoints); - describe('list_api_endpoints', () => { - const listEndpointsTool = tools.find((tool) => tool.tool.name === 'list_api_endpoints'); + const toolsMap = { + list_api_endpoints: toolOrError('list_api_endpoints'), + get_api_endpoint_schema: toolOrError('get_api_endpoint_schema'), + invoke_api_endpoint: toolOrError('invoke_api_endpoint'), + }; + describe('list_api_endpoints', () => { it('should return all endpoints when no search query is provided', async () => { - if (!listEndpointsTool) fail('list_api_endpoints tool not found'); - - const result = await listEndpointsTool.handler(fakeClient, {}); + const result = await toolsMap.list_api_endpoints.handler(fakeClient, {}); expect(result.tools).toHaveLength(endpoints.length); expect(result.tools.map((t: { name: string }) => t.name)).toContain('test_read_endpoint'); @@ -29,36 +31,28 @@ describe('dynamicTools', () => { }); it('should filter endpoints by name', async () => { - if (!listEndpointsTool) fail('list_api_endpoints tool not found'); - - const result = await listEndpointsTool.handler(fakeClient, { search_query: 'user' }); + const result = await toolsMap.list_api_endpoints.handler(fakeClient, { search_query: 'user' }); expect(result.tools).toHaveLength(1); expect(result.tools[0].name).toBe('user_endpoint'); }); it('should filter endpoints by resource', async () => { - if (!listEndpointsTool) fail('list_api_endpoints tool not found'); - - const result = await listEndpointsTool.handler(fakeClient, { search_query: 'admin' }); + const result = await toolsMap.list_api_endpoints.handler(fakeClient, { search_query: 'admin' }); expect(result.tools.some((t: { resource: string }) => t.resource === 'admin')).toBeTruthy(); }); it('should filter endpoints by tag', async () => { - if (!listEndpointsTool) fail('list_api_endpoints tool not found'); - - const result = await listEndpointsTool.handler(fakeClient, { search_query: 'admin' }); + const result = await toolsMap.list_api_endpoints.handler(fakeClient, { search_query: 'admin' }); expect(result.tools.some((t: { tags: string[] }) => t.tags.includes('admin'))).toBeTruthy(); }); it('should be case insensitive in search', async () => { - if (!listEndpointsTool) fail('list_api_endpoints tool not found'); + const result = await toolsMap.list_api_endpoints.handler(fakeClient, { search_query: 'ADMIN' }); - const result = await listEndpointsTool.handler(fakeClient, { search_query: 'ADMIN' }); - - expect(result.tools.length).toBeGreaterThan(0); + expect(result.tools.length).toBe(2); result.tools.forEach((tool: { name: string; resource: string; tags: string[] }) => { expect( tool.name.toLowerCase().includes('admin') || @@ -67,46 +61,55 @@ describe('dynamicTools', () => { ).toBeTruthy(); }); }); + + it('should filter endpoints by description', async () => { + const result = await toolsMap.list_api_endpoints.handler(fakeClient, { + search_query: 'Test endpoint for user_endpoint', + }); + + expect(result.tools).toHaveLength(1); + expect(result.tools[0].name).toBe('user_endpoint'); + expect(result.tools[0].description).toBe('Test endpoint for user_endpoint'); + }); + + it('should filter endpoints by partial description match', async () => { + const result = await toolsMap.list_api_endpoints.handler(fakeClient, { + search_query: 'endpoint for user', + }); + + expect(result.tools).toHaveLength(1); + expect(result.tools[0].name).toBe('user_endpoint'); + }); }); describe('get_api_endpoint_schema', () => { - const getEndpointSchemaTool = tools.find((tool) => tool.tool.name === 'get_api_endpoint_schema'); - it('should return schema for existing endpoint', async () => { - if (!getEndpointSchemaTool) fail('get_api_endpoint_schema tool not found'); - - const result = await getEndpointSchemaTool.handler(fakeClient, { endpoint: 'test_read_endpoint' }); + const result = await toolsMap.get_api_endpoint_schema.handler(fakeClient, { + endpoint: 'test_read_endpoint', + }); expect(result).toEqual(endpoints[0]?.tool); }); it('should throw error for non-existent endpoint', async () => { - if (!getEndpointSchemaTool) fail('get_api_endpoint_schema tool not found'); - await expect( - getEndpointSchemaTool.handler(fakeClient, { endpoint: 'non_existent_endpoint' }), + toolsMap.get_api_endpoint_schema.handler(fakeClient, { endpoint: 'non_existent_endpoint' }), ).rejects.toThrow('Endpoint non_existent_endpoint not found'); }); it('should throw error when no endpoint provided', async () => { - if (!getEndpointSchemaTool) fail('get_api_endpoint_schema tool not found'); - - await expect(getEndpointSchemaTool.handler(fakeClient, undefined)).rejects.toThrow( + await expect(toolsMap.get_api_endpoint_schema.handler(fakeClient, undefined)).rejects.toThrow( 'No endpoint provided', ); }); }); describe('invoke_api_endpoint', () => { - const invokeEndpointTool = tools.find((tool) => tool.tool.name === 'invoke_api_endpoint'); - it('should successfully invoke endpoint with valid arguments', async () => { - if (!invokeEndpointTool) fail('invoke_api_endpoint tool not found'); - const mockHandler = endpoints[0]?.handler as jest.Mock; mockHandler.mockClear(); - await invokeEndpointTool.handler(fakeClient, { + await toolsMap.invoke_api_endpoint.handler(fakeClient, { endpoint_name: 'test_read_endpoint', args: { testParam: 'test value' }, }); @@ -115,10 +118,8 @@ describe('dynamicTools', () => { }); it('should throw error for non-existent endpoint', async () => { - if (!invokeEndpointTool) fail('invoke_api_endpoint tool not found'); - await expect( - invokeEndpointTool.handler(fakeClient, { + toolsMap.invoke_api_endpoint.handler(fakeClient, { endpoint_name: 'non_existent_endpoint', args: { testParam: 'test value' }, }), @@ -126,22 +127,26 @@ describe('dynamicTools', () => { }); it('should throw error when no arguments provided', async () => { - if (!invokeEndpointTool) fail('invoke_api_endpoint tool not found'); - - await expect(invokeEndpointTool.handler(fakeClient, undefined)).rejects.toThrow('No endpoint provided'); + await expect(toolsMap.invoke_api_endpoint.handler(fakeClient, undefined)).rejects.toThrow( + 'No endpoint provided', + ); }); it('should throw error for invalid argument schema', async () => { - if (!invokeEndpointTool) fail('invoke_api_endpoint tool not found'); - await expect( - invokeEndpointTool.handler(fakeClient, { + toolsMap.invoke_api_endpoint.handler(fakeClient, { endpoint_name: 'test_read_endpoint', args: { wrongParam: 'test value' }, // Missing required testParam }), ).rejects.toThrow(/Invalid arguments for endpoint/); }); }); + + function toolOrError(name: string) { + const tool = tools.find((tool) => tool.tool.name === name); + if (!tool) throw new Error(`Tool ${name} not found`); + return tool; + } }); function makeEndpoint( From 56049b624052cd839c46ad276b1cb50d09090319 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 28 May 2025 03:44:21 +0000 Subject: [PATCH 21/91] chore: improve publish-npm script --latest tag logic --- bin/publish-npm | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/bin/publish-npm b/bin/publish-npm index 4c21181..2505dec 100644 --- a/bin/publish-npm +++ b/bin/publish-npm @@ -4,19 +4,35 @@ set -eux npm config set '//registry.npmjs.org/:_authToken' "$NPM_TOKEN" -# Build the project yarn build - -# Navigate to the dist directory cd dist -# Get the version from package.json +# Get latest version from npm +# +# If the package doesn't exist, yarn will return +# {"type":"error","data":"Received invalid response from npm."} +# where .data.version doesn't exist so LAST_VERSION will be an empty string. +LAST_VERSION="$(yarn info --json 2> /dev/null | jq -r '.data.version')" + +# Get current version from package.json VERSION="$(node -p "require('./package.json').version")" -# Extract the pre-release tag if it exists +# Check if current version is pre-release (e.g. alpha / beta / rc) +CURRENT_IS_PRERELEASE=false if [[ "$VERSION" =~ -([a-zA-Z]+) ]]; then - # Extract the part before any dot in the pre-release identifier - TAG="${BASH_REMATCH[1]}" + CURRENT_IS_PRERELEASE=true + CURRENT_TAG="${BASH_REMATCH[1]}" +fi + +# Check if last version is a stable release +LAST_IS_STABLE_RELEASE=true +if [[ -z "$LAST_VERSION" || "$LAST_VERSION" =~ -([a-zA-Z]+) ]]; then + LAST_IS_STABLE_RELEASE=false +fi + +# Use a corresponding alpha/beta tag if there already is a stable release and we're publishing a prerelease. +if $CURRENT_IS_PRERELEASE && $LAST_IS_STABLE_RELEASE; then + TAG="$CURRENT_TAG" else TAG="latest" fi From 1f16c337b9468640fc0a97dde7d958dac0cfc99c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 29 May 2025 02:52:14 +0000 Subject: [PATCH 22/91] feat(mcp): include http information in tools --- packages/mcp-server/src/tools/events/list-events.ts | 3 +++ packages/mcp-server/src/tools/files/delete-files.ts | 3 +++ packages/mcp-server/src/tools/files/download-files.ts | 3 +++ packages/mcp-server/src/tools/files/list-files.ts | 3 +++ packages/mcp-server/src/tools/files/retrieve-files.ts | 3 +++ packages/mcp-server/src/tools/files/upload-files.ts | 3 +++ .../tools/image-operations/apply-effect-image-operations.ts | 3 +++ .../src/tools/image-operations/convert-image-operations.ts | 3 +++ .../image-operations/detect-documents-image-operations.ts | 3 +++ .../tools/image-operations/extract-text-image-operations.ts | 3 +++ .../src/tools/image-operations/warp-image-operations.ts | 3 +++ packages/mcp-server/src/tools/index.ts | 4 ++++ .../src/tools/pdf-operations/extract-pages-pdf-operations.ts | 3 +++ .../src/tools/pdf-operations/merge-pdf-operations.ts | 3 +++ .../src/tools/pdf-operations/render-pdf-operations.ts | 3 +++ .../src/tools/pdf-operations/split-pdf-operations.ts | 3 +++ packages/mcp-server/src/tools/tasks/list-tasks.ts | 3 +++ packages/mcp-server/src/tools/tasks/retrieve-tasks.ts | 3 +++ 18 files changed, 55 insertions(+) diff --git a/packages/mcp-server/src/tools/events/list-events.ts b/packages/mcp-server/src/tools/events/list-events.ts index 09c1b70..0ea20b1 100644 --- a/packages/mcp-server/src/tools/events/list-events.ts +++ b/packages/mcp-server/src/tools/events/list-events.ts @@ -8,6 +8,9 @@ export const metadata: Metadata = { resource: 'events', operation: 'read', tags: [], + httpMethod: 'get', + httpPath: '/v1/events', + operationId: 'listEvents', }; export const tool: Tool = { diff --git a/packages/mcp-server/src/tools/files/delete-files.ts b/packages/mcp-server/src/tools/files/delete-files.ts index bfa290b..dda1a84 100644 --- a/packages/mcp-server/src/tools/files/delete-files.ts +++ b/packages/mcp-server/src/tools/files/delete-files.ts @@ -8,6 +8,9 @@ export const metadata: Metadata = { resource: 'files', operation: 'write', tags: [], + httpMethod: 'delete', + httpPath: '/v1/files/{id}', + operationId: 'deleteFile', }; export const tool: Tool = { diff --git a/packages/mcp-server/src/tools/files/download-files.ts b/packages/mcp-server/src/tools/files/download-files.ts index cd8c759..d4e3adb 100644 --- a/packages/mcp-server/src/tools/files/download-files.ts +++ b/packages/mcp-server/src/tools/files/download-files.ts @@ -8,6 +8,9 @@ export const metadata: Metadata = { resource: 'files', operation: 'read', tags: [], + httpMethod: 'get', + httpPath: '/v1/files/{id}/download', + operationId: 'downloadFile', }; export const tool: Tool = { diff --git a/packages/mcp-server/src/tools/files/list-files.ts b/packages/mcp-server/src/tools/files/list-files.ts index 6482460..e129c18 100644 --- a/packages/mcp-server/src/tools/files/list-files.ts +++ b/packages/mcp-server/src/tools/files/list-files.ts @@ -8,6 +8,9 @@ export const metadata: Metadata = { resource: 'files', operation: 'read', tags: [], + httpMethod: 'get', + httpPath: '/v1/files', + operationId: 'listFiles', }; export const tool: Tool = { diff --git a/packages/mcp-server/src/tools/files/retrieve-files.ts b/packages/mcp-server/src/tools/files/retrieve-files.ts index de4ab3e..b536524 100644 --- a/packages/mcp-server/src/tools/files/retrieve-files.ts +++ b/packages/mcp-server/src/tools/files/retrieve-files.ts @@ -8,6 +8,9 @@ export const metadata: Metadata = { resource: 'files', operation: 'read', tags: [], + httpMethod: 'get', + httpPath: '/v1/files/{id}', + operationId: 'getFile', }; export const tool: Tool = { diff --git a/packages/mcp-server/src/tools/files/upload-files.ts b/packages/mcp-server/src/tools/files/upload-files.ts index 6bc76b4..c0e010f 100644 --- a/packages/mcp-server/src/tools/files/upload-files.ts +++ b/packages/mcp-server/src/tools/files/upload-files.ts @@ -8,6 +8,9 @@ export const metadata: Metadata = { resource: 'files', operation: 'write', tags: [], + httpMethod: 'post', + httpPath: '/v1/files', + operationId: 'uploadFile', }; export const tool: Tool = { diff --git a/packages/mcp-server/src/tools/image-operations/apply-effect-image-operations.ts b/packages/mcp-server/src/tools/image-operations/apply-effect-image-operations.ts index 6d2ac86..30398ce 100644 --- a/packages/mcp-server/src/tools/image-operations/apply-effect-image-operations.ts +++ b/packages/mcp-server/src/tools/image-operations/apply-effect-image-operations.ts @@ -8,6 +8,9 @@ export const metadata: Metadata = { resource: 'image_operations', operation: 'write', tags: [], + httpMethod: 'post', + httpPath: '/v1/image-operations/apply-effect', + operationId: 'applyEffect', }; export const tool: Tool = { diff --git a/packages/mcp-server/src/tools/image-operations/convert-image-operations.ts b/packages/mcp-server/src/tools/image-operations/convert-image-operations.ts index 1cf1099..b0f25cf 100644 --- a/packages/mcp-server/src/tools/image-operations/convert-image-operations.ts +++ b/packages/mcp-server/src/tools/image-operations/convert-image-operations.ts @@ -8,6 +8,9 @@ export const metadata: Metadata = { resource: 'image_operations', operation: 'write', tags: [], + httpMethod: 'post', + httpPath: '/v1/image-operations/convert', + operationId: 'convertImage', }; export const tool: Tool = { diff --git a/packages/mcp-server/src/tools/image-operations/detect-documents-image-operations.ts b/packages/mcp-server/src/tools/image-operations/detect-documents-image-operations.ts index b4c59a9..c5301af 100644 --- a/packages/mcp-server/src/tools/image-operations/detect-documents-image-operations.ts +++ b/packages/mcp-server/src/tools/image-operations/detect-documents-image-operations.ts @@ -8,6 +8,9 @@ export const metadata: Metadata = { resource: 'image_operations', operation: 'write', tags: [], + httpMethod: 'post', + httpPath: '/v1/image-operations/detect-documents', + operationId: 'detectDocuments', }; export const tool: Tool = { diff --git a/packages/mcp-server/src/tools/image-operations/extract-text-image-operations.ts b/packages/mcp-server/src/tools/image-operations/extract-text-image-operations.ts index 0bed11f..292edd3 100644 --- a/packages/mcp-server/src/tools/image-operations/extract-text-image-operations.ts +++ b/packages/mcp-server/src/tools/image-operations/extract-text-image-operations.ts @@ -8,6 +8,9 @@ export const metadata: Metadata = { resource: 'image_operations', operation: 'write', tags: [], + httpMethod: 'post', + httpPath: '/v1/image-operations/extract-text', + operationId: 'extractText', }; export const tool: Tool = { diff --git a/packages/mcp-server/src/tools/image-operations/warp-image-operations.ts b/packages/mcp-server/src/tools/image-operations/warp-image-operations.ts index 6e546f9..c45a911 100644 --- a/packages/mcp-server/src/tools/image-operations/warp-image-operations.ts +++ b/packages/mcp-server/src/tools/image-operations/warp-image-operations.ts @@ -8,6 +8,9 @@ export const metadata: Metadata = { resource: 'image_operations', operation: 'write', tags: [], + httpMethod: 'post', + httpPath: '/v1/image-operations/warp', + operationId: 'warpImage', }; export const tool: Tool = { diff --git a/packages/mcp-server/src/tools/index.ts b/packages/mcp-server/src/tools/index.ts index 4ab0cd3..8e5f3a0 100644 --- a/packages/mcp-server/src/tools/index.ts +++ b/packages/mcp-server/src/tools/index.ts @@ -30,6 +30,10 @@ export type Metadata = { resource: string; operation: 'read' | 'write'; tags: string[]; + + httpMethod?: string; + httpPath?: string; + operationId?: string; }; export type Endpoint = { diff --git a/packages/mcp-server/src/tools/pdf-operations/extract-pages-pdf-operations.ts b/packages/mcp-server/src/tools/pdf-operations/extract-pages-pdf-operations.ts index 7147b8c..96ced65 100644 --- a/packages/mcp-server/src/tools/pdf-operations/extract-pages-pdf-operations.ts +++ b/packages/mcp-server/src/tools/pdf-operations/extract-pages-pdf-operations.ts @@ -8,6 +8,9 @@ export const metadata: Metadata = { resource: 'pdf_operations', operation: 'write', tags: [], + httpMethod: 'post', + httpPath: '/v1/pdf-operations/extract-pages', + operationId: 'extractPdfPages', }; export const tool: Tool = { diff --git a/packages/mcp-server/src/tools/pdf-operations/merge-pdf-operations.ts b/packages/mcp-server/src/tools/pdf-operations/merge-pdf-operations.ts index d543d4f..dfc5ea6 100644 --- a/packages/mcp-server/src/tools/pdf-operations/merge-pdf-operations.ts +++ b/packages/mcp-server/src/tools/pdf-operations/merge-pdf-operations.ts @@ -8,6 +8,9 @@ export const metadata: Metadata = { resource: 'pdf_operations', operation: 'write', tags: [], + httpMethod: 'post', + httpPath: '/v1/pdf-operations/merge', + operationId: 'mergePdf', }; export const tool: Tool = { diff --git a/packages/mcp-server/src/tools/pdf-operations/render-pdf-operations.ts b/packages/mcp-server/src/tools/pdf-operations/render-pdf-operations.ts index 34e43c2..cc66161 100644 --- a/packages/mcp-server/src/tools/pdf-operations/render-pdf-operations.ts +++ b/packages/mcp-server/src/tools/pdf-operations/render-pdf-operations.ts @@ -8,6 +8,9 @@ export const metadata: Metadata = { resource: 'pdf_operations', operation: 'write', tags: [], + httpMethod: 'post', + httpPath: '/v1/pdf-operations/render', + operationId: 'renderPdf', }; export const tool: Tool = { diff --git a/packages/mcp-server/src/tools/pdf-operations/split-pdf-operations.ts b/packages/mcp-server/src/tools/pdf-operations/split-pdf-operations.ts index 2aca4c6..8dbe344 100644 --- a/packages/mcp-server/src/tools/pdf-operations/split-pdf-operations.ts +++ b/packages/mcp-server/src/tools/pdf-operations/split-pdf-operations.ts @@ -8,6 +8,9 @@ export const metadata: Metadata = { resource: 'pdf_operations', operation: 'write', tags: [], + httpMethod: 'post', + httpPath: '/v1/pdf-operations/split', + operationId: 'splitPdf', }; export const tool: Tool = { diff --git a/packages/mcp-server/src/tools/tasks/list-tasks.ts b/packages/mcp-server/src/tools/tasks/list-tasks.ts index 1d0182f..1fb8ee0 100644 --- a/packages/mcp-server/src/tools/tasks/list-tasks.ts +++ b/packages/mcp-server/src/tools/tasks/list-tasks.ts @@ -8,6 +8,9 @@ export const metadata: Metadata = { resource: 'tasks', operation: 'read', tags: [], + httpMethod: 'get', + httpPath: '/v1/tasks', + operationId: 'listTasks', }; export const tool: Tool = { diff --git a/packages/mcp-server/src/tools/tasks/retrieve-tasks.ts b/packages/mcp-server/src/tools/tasks/retrieve-tasks.ts index 3b422de..a39c2d6 100644 --- a/packages/mcp-server/src/tools/tasks/retrieve-tasks.ts +++ b/packages/mcp-server/src/tools/tasks/retrieve-tasks.ts @@ -8,6 +8,9 @@ export const metadata: Metadata = { resource: 'tasks', operation: 'read', tags: [], + httpMethod: 'get', + httpPath: '/v1/tasks/{id}', + operationId: 'getTask', }; export const tool: Tool = { From cbe063b80039e95e94941d42fd4900b977f73c6e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 29 May 2025 03:04:29 +0000 Subject: [PATCH 23/91] chore(mcp): remove duplicate assignment --- packages/mcp-server/src/server.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/mcp-server/src/server.ts b/packages/mcp-server/src/server.ts index a943e9a..388c0d2 100644 --- a/packages/mcp-server/src/server.ts +++ b/packages/mcp-server/src/server.ts @@ -97,7 +97,7 @@ export async function executeHandler( ) { const options = { ...defaultClientCapabilities, ...compatibilityOptions }; if (options.validJson && args) { - args = args = parseEmbeddedJSON(args, tool.inputSchema); + args = parseEmbeddedJSON(args, tool.inputSchema); } const result = await handler(client, args || {}); return { From ad4dcc71e8ae2df922f692b1c26601a718c085bb Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 30 May 2025 03:28:59 +0000 Subject: [PATCH 24/91] fix: compat with more runtimes --- src/internal/detect-platform.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/internal/detect-platform.ts b/src/internal/detect-platform.ts index c5e273b..e82d95c 100644 --- a/src/internal/detect-platform.ts +++ b/src/internal/detect-platform.ts @@ -85,10 +85,10 @@ const getPlatformProperties = (): PlatformProperties => { return { 'X-Stainless-Lang': 'js', 'X-Stainless-Package-Version': VERSION, - 'X-Stainless-OS': normalizePlatform((globalThis as any).process.platform), - 'X-Stainless-Arch': normalizeArch((globalThis as any).process.arch), + 'X-Stainless-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, + 'X-Stainless-Runtime-Version': (globalThis as any).process.version ?? 'unknown', }; } From 5e847511f406b21ffe9ff50ed5884b4a21d8025a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 31 May 2025 03:13:28 +0000 Subject: [PATCH 25/91] chore(deps): bump eslint-plugin-prettier --- package.json | 5 +---- yarn.lock | 34 ++++++++++++++-------------------- 2 files changed, 15 insertions(+), 24 deletions(-) diff --git a/package.json b/package.json index ba12075..0feff68 100644 --- a/package.json +++ b/package.json @@ -34,7 +34,7 @@ "@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-prettier": "^5.4.1", "eslint-plugin-unused-imports": "^4.1.4", "iconv-lite": "^0.6.3", "jest": "^29.4.0", @@ -46,9 +46,6 @@ "tsconfig-paths": "^4.0.0", "typescript": "5.8.3" }, - "resolutions": { - "synckit": "0.8.8" - }, "imports": { "scan-documents": ".", "scan-documents/*": "./src/*" diff --git a/yarn.lock b/yarn.lock index 43da555..49d3eb8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -714,10 +714,10 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.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== +"@pkgr/core@^0.2.4": + version "0.2.4" + resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.2.4.tgz#d897170a2b0ba51f78a099edccd968f7b103387c" + integrity sha512-ROFF39F6ZrnzSUEmQQZUar0Jt4xVoP9WnDRdWwF4NNcXs3xBTLgBUDoOwW141y1jP+S8nahIbdxbFC7IShw9Iw== "@sinclair/typebox@^0.27.8": version "0.27.8" @@ -1547,13 +1547,13 @@ 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.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== +eslint-plugin-prettier@^5.4.1: + version "5.4.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.4.1.tgz#99b55d7dd70047886b2222fdd853665f180b36af" + integrity sha512-9dF+KuU/Ilkq27A8idRP7N2DH8iUR6qXcjF3FR2wETY21PZdBrIjwCau8oboyGj9b7etWmTGEeM8e7oOed6ZWg== dependencies: prettier-linter-helpers "^1.0.0" - synckit "^0.9.1" + synckit "^0.11.7" eslint-plugin-unused-imports@^4.1.4: version "4.1.4" @@ -3198,13 +3198,12 @@ supports-preserve-symlinks-flag@^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.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== +synckit@^0.11.7: + version "0.11.8" + resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.11.8.tgz#b2aaae998a4ef47ded60773ad06e7cb821f55457" + integrity sha512-+XZ+r1XGIJGeQk3VvXhT6xx/VpbHsRzsTkGgF6E5RX9TTXD0118l87puaEBZ566FhqblC6U0d4XnubznJDm30A== dependencies: - "@pkgr/core" "^0.1.0" - tslib "^2.6.2" + "@pkgr/core" "^0.2.4" test-exclude@^6.0.0: version "6.0.0" @@ -3308,11 +3307,6 @@ tsconfig-paths@^4.0.0: minimist "^1.2.6" strip-bom "^3.0.0" -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" From 64bfd6d3eb76e22d1c8da474d9d78c93643db14c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 31 May 2025 03:25:53 +0000 Subject: [PATCH 26/91] chore(internal): update jest config --- jest.config.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/jest.config.ts b/jest.config.ts index 81d36c7..1d86472 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -15,6 +15,7 @@ const config: JestConfigWithTsJest = { '/dist/', '/deno/', '/deno_tests/', + '/packages/', ], testPathIgnorePatterns: ['scripts'], }; From 08d4622daf787077bed5f5b199d907ccc58acc05 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 3 Jun 2025 04:33:28 +0000 Subject: [PATCH 27/91] chore: adjust eslint.config.mjs ignore pattern --- eslint.config.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/eslint.config.mjs b/eslint.config.mjs index a4591a8..b386e66 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -10,7 +10,7 @@ export default tseslint.config( parserOptions: { sourceType: 'module' }, }, files: ['**/*.ts', '**/*.mts', '**/*.cts', '**/*.js', '**/*.mjs', '**/*.cjs'], - ignores: ['dist/**'], + ignores: ['dist/'], plugins: { '@typescript-eslint': tseslint.plugin, 'unused-imports': unusedImports, From eb56b2bbf195db6718d8680fde40f9fabe3c5af1 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 4 Jun 2025 03:59:14 +0000 Subject: [PATCH 28/91] chore(docs): use top-level-await in example snippets --- README.md | 46 +++++++++++++++++----------------------------- 1 file changed, 17 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index 762d200..b30fc51 100644 --- a/README.md +++ b/README.md @@ -26,11 +26,7 @@ const client = new ScanDocuments({ apiKey: process.env['SCAN_DOCUMENTS_API_KEY'], // This is the default and can be omitted }); -async function main() { - const file = await client.files.upload({ file: fs.createReadStream('path/to/file'), name: 'REPLACE_ME' }); -} - -main(); +const file = await client.files.upload({ file: fs.createReadStream('path/to/file'), name: 'REPLACE_ME' }); ``` ### Request & Response types @@ -45,15 +41,11 @@ const client = new ScanDocuments({ apiKey: process.env['SCAN_DOCUMENTS_API_KEY'], // This is the default and can be omitted }); -async function main() { - const params: ScanDocuments.FileUploadParams = { - file: fs.createReadStream('path/to/file'), - name: 'REPLACE_ME', - }; - const file: ScanDocuments.File = await client.files.upload(params); -} - -main(); +const params: ScanDocuments.FileUploadParams = { + file: fs.createReadStream('path/to/file'), + name: 'REPLACE_ME', +}; +const file: ScanDocuments.File = await client.files.upload(params); ``` Documentation for each method, request param, and response field are available in docstrings and will appear on hover in most modern editors. @@ -95,21 +87,17 @@ a subclass of `APIError` will be thrown: ```ts -async function main() { - const file = await client.files - .upload({ file: fs.createReadStream('path/to/file'), name: 'REPLACE_ME' }) - .catch(async (err) => { - if (err instanceof ScanDocuments.APIError) { - console.log(err.status); // 400 - console.log(err.name); // BadRequestError - console.log(err.headers); // {server: 'nginx', ...} - } else { - throw err; - } - }); -} - -main(); +const file = await client.files + .upload({ file: fs.createReadStream('path/to/file'), name: 'REPLACE_ME' }) + .catch(async (err) => { + if (err instanceof ScanDocuments.APIError) { + console.log(err.status); // 400 + console.log(err.name); // BadRequestError + console.log(err.headers); // {server: 'nginx', ...} + } else { + throw err; + } + }); ``` Error codes are as follows: From 94550b657c2566ae6df3bcf557a614066772e54a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 4 Jun 2025 04:29:21 +0000 Subject: [PATCH 29/91] chore(internal): fix readablestream types in node 20 --- scripts/build | 2 -- src/internal/shim-types.d.ts | 28 ---------------------------- src/internal/shim-types.ts | 26 ++++++++++++++++++++++++++ src/internal/shims.ts | 4 ++-- 4 files changed, 28 insertions(+), 32 deletions(-) delete mode 100644 src/internal/shim-types.d.ts create mode 100644 src/internal/shim-types.ts diff --git a/scripts/build b/scripts/build index 9d3d404..1414a02 100755 --- a/scripts/build +++ b/scripts/build @@ -37,8 +37,6 @@ npm exec tsc-multi # when building .mjs node scripts/utils/fix-index-exports.cjs 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/src/internal/shim-types.d.ts b/src/internal/shim-types.d.ts deleted file mode 100644 index fe48144..0000000 --- a/src/internal/shim-types.d.ts +++ /dev/null @@ -1,28 +0,0 @@ -// 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/shim-types.ts b/src/internal/shim-types.ts new file mode 100644 index 0000000..8ddf7b0 --- /dev/null +++ b/src/internal/shim-types.ts @@ -0,0 +1,26 @@ +// 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. + */ + +type NeverToAny = T extends never ? any : T; + +/** @ts-ignore */ +type _DOMReadableStream = globalThis.ReadableStream; + +/** @ts-ignore */ +type _NodeReadableStream = import('stream/web').ReadableStream; + +type _ConditionalNodeReadableStream = + typeof globalThis extends { ReadableStream: any } ? never : _NodeReadableStream; + +type _ReadableStream = NeverToAny< + | ([0] extends [1 & _DOMReadableStream] ? never : _DOMReadableStream) + | ([0] extends [1 & _ConditionalNodeReadableStream] ? never : _ConditionalNodeReadableStream) +>; + +export type { _ReadableStream as ReadableStream }; diff --git a/src/internal/shims.ts b/src/internal/shims.ts index 05ee204..32dd47f 100644 --- a/src/internal/shims.ts +++ b/src/internal/shims.ts @@ -7,8 +7,8 @@ * messages in cases where an environment isn't fully supported. */ -import { type Fetch } from './builtin-types'; -import { type ReadableStream } from './shim-types'; +import type { Fetch } from './builtin-types'; +import type { ReadableStream } from './shim-types'; export function getDefaultFetch(): Fetch { if (typeof fetch !== 'undefined') { From 95c7f8638bfc0e55704a417472b8729be7ea0406 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 6 Jun 2025 03:45:50 +0000 Subject: [PATCH 30/91] feat(mcp): implement support for binary responses --- packages/mcp-server/src/dynamic-tools.ts | 20 ++-- packages/mcp-server/src/server.ts | 10 +- .../src/tools/events/list-events.ts | 6 +- .../src/tools/files/delete-files.ts | 7 +- .../src/tools/files/download-files.ts | 6 +- .../mcp-server/src/tools/files/list-files.ts | 6 +- .../src/tools/files/retrieve-files.ts | 6 +- .../src/tools/files/upload-files.ts | 6 +- .../apply-effect-image-operations.ts | 6 +- .../convert-image-operations.ts | 6 +- .../detect-documents-image-operations.ts | 6 +- .../extract-text-image-operations.ts | 6 +- .../image-operations/warp-image-operations.ts | 6 +- packages/mcp-server/src/tools/index.ts | 26 +---- .../extract-pages-pdf-operations.ts | 6 +- .../pdf-operations/merge-pdf-operations.ts | 6 +- .../pdf-operations/render-pdf-operations.ts | 6 +- .../pdf-operations/split-pdf-operations.ts | 6 +- .../mcp-server/src/tools/tasks/list-tasks.ts | 6 +- .../src/tools/tasks/retrieve-tasks.ts | 6 +- packages/mcp-server/src/tools/types.ts | 104 ++++++++++++++++++ .../mcp-server/tests/dynamic-tools.test.ts | 24 ++-- 22 files changed, 206 insertions(+), 81 deletions(-) create mode 100644 packages/mcp-server/src/tools/types.ts diff --git a/packages/mcp-server/src/dynamic-tools.ts b/packages/mcp-server/src/dynamic-tools.ts index d184ee8..f6870b4 100644 --- a/packages/mcp-server/src/dynamic-tools.ts +++ b/packages/mcp-server/src/dynamic-tools.ts @@ -1,5 +1,5 @@ import ScanDocuments from 'scan-documents'; -import { Endpoint } from './tools'; +import { Endpoint, asTextContentResult, ToolCallResult } from './tools/types'; import { zodToJsonSchema } from 'zod-to-json-schema'; import { z } from 'zod'; import { Cabidela } from '@cloudflare/cabidela'; @@ -41,7 +41,10 @@ export function dynamicTools(endpoints: Endpoint[]): Endpoint[] { description: 'List or search for all endpoints in the Scan Documents TypeScript API', inputSchema: zodToInputSchema(listEndpointsSchema), }, - handler: async (client: ScanDocuments, args: Record | undefined) => { + handler: async ( + client: ScanDocuments, + args: Record | undefined, + ): Promise => { const query = args && listEndpointsSchema.parse(args).search_query?.trim(); const filteredEndpoints = @@ -58,7 +61,7 @@ export function dynamicTools(endpoints: Endpoint[]): Endpoint[] { }) : endpoints; - return { + return asTextContentResult({ tools: filteredEndpoints.map(({ tool, metadata }) => ({ name: tool.name, description: tool.description, @@ -66,7 +69,7 @@ export function dynamicTools(endpoints: Endpoint[]): Endpoint[] { operation: metadata.operation, tags: metadata.tags, })), - }; + }); }, }; @@ -95,7 +98,7 @@ export function dynamicTools(endpoints: Endpoint[]): Endpoint[] { if (!endpoint) { throw new Error(`Endpoint ${endpointName} not found`); } - return endpoint.tool; + return asTextContentResult(endpoint.tool); }, }; @@ -120,7 +123,10 @@ export function dynamicTools(endpoints: Endpoint[]): Endpoint[] { 'Invoke an endpoint in the Scan Documents TypeScript API. Note: use the `list_api_endpoints` tool to get the list of endpoints and `get_api_endpoint_schema` tool to get the schema for an endpoint.', inputSchema: zodToInputSchema(invokeEndpointSchema), }, - handler: async (client: ScanDocuments, args: Record | undefined) => { + handler: async ( + client: ScanDocuments, + args: Record | undefined, + ): Promise => { if (!args) { throw new Error('No endpoint provided'); } @@ -145,7 +151,7 @@ export function dynamicTools(endpoints: Endpoint[]): Endpoint[] { throw new Error(`Invalid arguments for endpoint ${endpoint_name}:\n${error}`); } - return endpoint.handler(client, endpointArgs); + return await endpoint.handler(client, endpointArgs); }, }; diff --git a/packages/mcp-server/src/server.ts b/packages/mcp-server/src/server.ts index 388c0d2..70f2cb5 100644 --- a/packages/mcp-server/src/server.ts +++ b/packages/mcp-server/src/server.ts @@ -99,15 +99,7 @@ export async function executeHandler( if (options.validJson && args) { args = parseEmbeddedJSON(args, tool.inputSchema); } - const result = await handler(client, args || {}); - return { - content: [ - { - type: 'text', - text: JSON.stringify(result, null, 2), - }, - ], - }; + return await handler(client, args || {}); } export const readEnv = (env: string): string | undefined => { diff --git a/packages/mcp-server/src/tools/events/list-events.ts b/packages/mcp-server/src/tools/events/list-events.ts index 0ea20b1..6dc693f 100644 --- a/packages/mcp-server/src/tools/events/list-events.ts +++ b/packages/mcp-server/src/tools/events/list-events.ts @@ -1,5 +1,7 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +import { asTextContentResult } from 'scan-documents-mcp/tools/types'; + import { Tool } from '@modelcontextprotocol/sdk/types.js'; import type { Metadata } from '../'; import ScanDocuments from 'scan-documents'; @@ -29,9 +31,9 @@ export const tool: Tool = { }, }; -export const handler = (client: ScanDocuments, args: Record | undefined) => { +export const handler = async (client: ScanDocuments, args: Record | undefined) => { const body = args as any; - return client.events.list(body); + return asTextContentResult(await client.events.list(body)); }; export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/files/delete-files.ts b/packages/mcp-server/src/tools/files/delete-files.ts index dda1a84..55141de 100644 --- a/packages/mcp-server/src/tools/files/delete-files.ts +++ b/packages/mcp-server/src/tools/files/delete-files.ts @@ -1,5 +1,7 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +import { asTextContentResult } from 'scan-documents-mcp/tools/types'; + import { Tool } from '@modelcontextprotocol/sdk/types.js'; import type { Metadata } from '../'; import ScanDocuments from 'scan-documents'; @@ -26,9 +28,10 @@ export const tool: Tool = { }, }; -export const handler = (client: ScanDocuments, args: Record | undefined) => { +export const handler = async (client: ScanDocuments, args: Record | undefined) => { const { id, ...body } = args as any; - return client.files.delete(id); + await client.files.delete(id); + return asTextContentResult('Successful tool call'); }; export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/files/download-files.ts b/packages/mcp-server/src/tools/files/download-files.ts index d4e3adb..564189c 100644 --- a/packages/mcp-server/src/tools/files/download-files.ts +++ b/packages/mcp-server/src/tools/files/download-files.ts @@ -1,5 +1,7 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +import { asBinaryContentResult } from 'scan-documents-mcp/tools/types'; + import { Tool } from '@modelcontextprotocol/sdk/types.js'; import type { Metadata } from '../'; import ScanDocuments from 'scan-documents'; @@ -26,9 +28,9 @@ export const tool: Tool = { }, }; -export const handler = (client: ScanDocuments, args: Record | undefined) => { +export const handler = async (client: ScanDocuments, args: Record | undefined) => { const { id, ...body } = args as any; - return client.files.download(id); + return asBinaryContentResult(await client.files.download(id)); }; export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/files/list-files.ts b/packages/mcp-server/src/tools/files/list-files.ts index e129c18..4419839 100644 --- a/packages/mcp-server/src/tools/files/list-files.ts +++ b/packages/mcp-server/src/tools/files/list-files.ts @@ -1,5 +1,7 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +import { asTextContentResult } from 'scan-documents-mcp/tools/types'; + import { Tool } from '@modelcontextprotocol/sdk/types.js'; import type { Metadata } from '../'; import ScanDocuments from 'scan-documents'; @@ -31,9 +33,9 @@ export const tool: Tool = { }, }; -export const handler = (client: ScanDocuments, args: Record | undefined) => { +export const handler = async (client: ScanDocuments, args: Record | undefined) => { const body = args as any; - return client.files.list(body); + return asTextContentResult(await client.files.list(body)); }; export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/files/retrieve-files.ts b/packages/mcp-server/src/tools/files/retrieve-files.ts index b536524..9b35a64 100644 --- a/packages/mcp-server/src/tools/files/retrieve-files.ts +++ b/packages/mcp-server/src/tools/files/retrieve-files.ts @@ -1,5 +1,7 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +import { asTextContentResult } from 'scan-documents-mcp/tools/types'; + import { Tool } from '@modelcontextprotocol/sdk/types.js'; import type { Metadata } from '../'; import ScanDocuments from 'scan-documents'; @@ -26,9 +28,9 @@ export const tool: Tool = { }, }; -export const handler = (client: ScanDocuments, args: Record | undefined) => { +export const handler = async (client: ScanDocuments, args: Record | undefined) => { const { id, ...body } = args as any; - return client.files.retrieve(id); + return asTextContentResult(await client.files.retrieve(id)); }; export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/files/upload-files.ts b/packages/mcp-server/src/tools/files/upload-files.ts index c0e010f..af089e9 100644 --- a/packages/mcp-server/src/tools/files/upload-files.ts +++ b/packages/mcp-server/src/tools/files/upload-files.ts @@ -1,5 +1,7 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +import { asTextContentResult } from 'scan-documents-mcp/tools/types'; + import { Tool } from '@modelcontextprotocol/sdk/types.js'; import type { Metadata } from '../'; import ScanDocuments from 'scan-documents'; @@ -31,9 +33,9 @@ export const tool: Tool = { }, }; -export const handler = (client: ScanDocuments, args: Record | undefined) => { +export const handler = async (client: ScanDocuments, args: Record | undefined) => { const body = args as any; - return client.files.upload(body); + return asTextContentResult(await client.files.upload(body)); }; export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/image-operations/apply-effect-image-operations.ts b/packages/mcp-server/src/tools/image-operations/apply-effect-image-operations.ts index 30398ce..ebe4942 100644 --- a/packages/mcp-server/src/tools/image-operations/apply-effect-image-operations.ts +++ b/packages/mcp-server/src/tools/image-operations/apply-effect-image-operations.ts @@ -1,5 +1,7 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +import { asTextContentResult } from 'scan-documents-mcp/tools/types'; + import { Tool } from '@modelcontextprotocol/sdk/types.js'; import type { Metadata } from '../'; import ScanDocuments from 'scan-documents'; @@ -36,9 +38,9 @@ export const tool: Tool = { }, }; -export const handler = (client: ScanDocuments, args: Record | undefined) => { +export const handler = async (client: ScanDocuments, args: Record | undefined) => { const body = args as any; - return client.imageOperations.applyEffect(body); + return asTextContentResult(await client.imageOperations.applyEffect(body)); }; export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/image-operations/convert-image-operations.ts b/packages/mcp-server/src/tools/image-operations/convert-image-operations.ts index b0f25cf..e889a16 100644 --- a/packages/mcp-server/src/tools/image-operations/convert-image-operations.ts +++ b/packages/mcp-server/src/tools/image-operations/convert-image-operations.ts @@ -1,5 +1,7 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +import { asTextContentResult } from 'scan-documents-mcp/tools/types'; + import { Tool } from '@modelcontextprotocol/sdk/types.js'; import type { Metadata } from '../'; import ScanDocuments from 'scan-documents'; @@ -85,9 +87,9 @@ export const tool: Tool = { }, }; -export const handler = (client: ScanDocuments, args: Record | undefined) => { +export const handler = async (client: ScanDocuments, args: Record | undefined) => { const body = args as any; - return client.imageOperations.convert(body); + return asTextContentResult(await client.imageOperations.convert(body)); }; export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/image-operations/detect-documents-image-operations.ts b/packages/mcp-server/src/tools/image-operations/detect-documents-image-operations.ts index c5301af..e78a757 100644 --- a/packages/mcp-server/src/tools/image-operations/detect-documents-image-operations.ts +++ b/packages/mcp-server/src/tools/image-operations/detect-documents-image-operations.ts @@ -1,5 +1,7 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +import { asTextContentResult } from 'scan-documents-mcp/tools/types'; + import { Tool } from '@modelcontextprotocol/sdk/types.js'; import type { Metadata } from '../'; import ScanDocuments from 'scan-documents'; @@ -27,9 +29,9 @@ export const tool: Tool = { }, }; -export const handler = (client: ScanDocuments, args: Record | undefined) => { +export const handler = async (client: ScanDocuments, args: Record | undefined) => { const body = args as any; - return client.imageOperations.detectDocuments(body); + return asTextContentResult(await client.imageOperations.detectDocuments(body)); }; export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/image-operations/extract-text-image-operations.ts b/packages/mcp-server/src/tools/image-operations/extract-text-image-operations.ts index 292edd3..a5d0e9d 100644 --- a/packages/mcp-server/src/tools/image-operations/extract-text-image-operations.ts +++ b/packages/mcp-server/src/tools/image-operations/extract-text-image-operations.ts @@ -1,5 +1,7 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +import { asTextContentResult } from 'scan-documents-mcp/tools/types'; + import { Tool } from '@modelcontextprotocol/sdk/types.js'; import type { Metadata } from '../'; import ScanDocuments from 'scan-documents'; @@ -117,9 +119,9 @@ export const tool: Tool = { }, }; -export const handler = (client: ScanDocuments, args: Record | undefined) => { +export const handler = async (client: ScanDocuments, args: Record | undefined) => { const body = args as any; - return client.imageOperations.extractText(body); + return asTextContentResult(await client.imageOperations.extractText(body)); }; export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/image-operations/warp-image-operations.ts b/packages/mcp-server/src/tools/image-operations/warp-image-operations.ts index c45a911..5d2552e 100644 --- a/packages/mcp-server/src/tools/image-operations/warp-image-operations.ts +++ b/packages/mcp-server/src/tools/image-operations/warp-image-operations.ts @@ -1,5 +1,7 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +import { asTextContentResult } from 'scan-documents-mcp/tools/types'; + import { Tool } from '@modelcontextprotocol/sdk/types.js'; import type { Metadata } from '../'; import ScanDocuments from 'scan-documents'; @@ -39,9 +41,9 @@ export const tool: Tool = { }, }; -export const handler = (client: ScanDocuments, args: Record | undefined) => { +export const handler = async (client: ScanDocuments, args: Record | undefined) => { const body = args as any; - return client.imageOperations.warp(body); + return asTextContentResult(await client.imageOperations.warp(body)); }; export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/index.ts b/packages/mcp-server/src/tools/index.ts index 8e5f3a0..cf4387f 100644 --- a/packages/mcp-server/src/tools/index.ts +++ b/packages/mcp-server/src/tools/index.ts @@ -1,7 +1,8 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import ScanDocuments from 'scan-documents'; -import { Tool } from '@modelcontextprotocol/sdk/types.js'; +import { Metadata, Endpoint, HandlerFunction } from './types'; + +export { Metadata, Endpoint, HandlerFunction }; import retrieve_files from './files/retrieve-files'; import list_files from './files/list-files'; @@ -21,27 +22,6 @@ import merge_pdf_operations from './pdf-operations/merge-pdf-operations'; import render_pdf_operations from './pdf-operations/render-pdf-operations'; import split_pdf_operations from './pdf-operations/split-pdf-operations'; -export type HandlerFunction = ( - client: ScanDocuments, - args: Record | undefined, -) => Promise; - -export type Metadata = { - resource: string; - operation: 'read' | 'write'; - tags: string[]; - - httpMethod?: string; - httpPath?: string; - operationId?: string; -}; - -export type Endpoint = { - metadata: Metadata; - tool: Tool; - handler: HandlerFunction; -}; - export const endpoints: Endpoint[] = []; function addEndpoint(endpoint: Endpoint) { diff --git a/packages/mcp-server/src/tools/pdf-operations/extract-pages-pdf-operations.ts b/packages/mcp-server/src/tools/pdf-operations/extract-pages-pdf-operations.ts index 96ced65..a45d3ac 100644 --- a/packages/mcp-server/src/tools/pdf-operations/extract-pages-pdf-operations.ts +++ b/packages/mcp-server/src/tools/pdf-operations/extract-pages-pdf-operations.ts @@ -1,5 +1,7 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +import { asTextContentResult } from 'scan-documents-mcp/tools/types'; + import { Tool } from '@modelcontextprotocol/sdk/types.js'; import type { Metadata } from '../'; import ScanDocuments from 'scan-documents'; @@ -35,9 +37,9 @@ export const tool: Tool = { }, }; -export const handler = (client: ScanDocuments, args: Record | undefined) => { +export const handler = async (client: ScanDocuments, args: Record | undefined) => { const body = args as any; - return client.pdfOperations.extractPages(body); + return asTextContentResult(await client.pdfOperations.extractPages(body)); }; export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/pdf-operations/merge-pdf-operations.ts b/packages/mcp-server/src/tools/pdf-operations/merge-pdf-operations.ts index dfc5ea6..7cc2adb 100644 --- a/packages/mcp-server/src/tools/pdf-operations/merge-pdf-operations.ts +++ b/packages/mcp-server/src/tools/pdf-operations/merge-pdf-operations.ts @@ -1,5 +1,7 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +import { asTextContentResult } from 'scan-documents-mcp/tools/types'; + import { Tool } from '@modelcontextprotocol/sdk/types.js'; import type { Metadata } from '../'; import ScanDocuments from 'scan-documents'; @@ -35,9 +37,9 @@ export const tool: Tool = { }, }; -export const handler = (client: ScanDocuments, args: Record | undefined) => { +export const handler = async (client: ScanDocuments, args: Record | undefined) => { const body = args as any; - return client.pdfOperations.merge(body); + return asTextContentResult(await client.pdfOperations.merge(body)); }; export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/pdf-operations/render-pdf-operations.ts b/packages/mcp-server/src/tools/pdf-operations/render-pdf-operations.ts index cc66161..328cdc4 100644 --- a/packages/mcp-server/src/tools/pdf-operations/render-pdf-operations.ts +++ b/packages/mcp-server/src/tools/pdf-operations/render-pdf-operations.ts @@ -1,5 +1,7 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +import { asTextContentResult } from 'scan-documents-mcp/tools/types'; + import { Tool } from '@modelcontextprotocol/sdk/types.js'; import type { Metadata } from '../'; import ScanDocuments from 'scan-documents'; @@ -39,9 +41,9 @@ export const tool: Tool = { }, }; -export const handler = (client: ScanDocuments, args: Record | undefined) => { +export const handler = async (client: ScanDocuments, args: Record | undefined) => { const body = args as any; - return client.pdfOperations.render(body); + return asTextContentResult(await client.pdfOperations.render(body)); }; export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/pdf-operations/split-pdf-operations.ts b/packages/mcp-server/src/tools/pdf-operations/split-pdf-operations.ts index 8dbe344..41ec959 100644 --- a/packages/mcp-server/src/tools/pdf-operations/split-pdf-operations.ts +++ b/packages/mcp-server/src/tools/pdf-operations/split-pdf-operations.ts @@ -1,5 +1,7 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +import { asTextContentResult } from 'scan-documents-mcp/tools/types'; + import { Tool } from '@modelcontextprotocol/sdk/types.js'; import type { Metadata } from '../'; import ScanDocuments from 'scan-documents'; @@ -31,9 +33,9 @@ export const tool: Tool = { }, }; -export const handler = (client: ScanDocuments, args: Record | undefined) => { +export const handler = async (client: ScanDocuments, args: Record | undefined) => { const body = args as any; - return client.pdfOperations.split(body); + return asTextContentResult(await client.pdfOperations.split(body)); }; export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/tasks/list-tasks.ts b/packages/mcp-server/src/tools/tasks/list-tasks.ts index 1fb8ee0..d57788e 100644 --- a/packages/mcp-server/src/tools/tasks/list-tasks.ts +++ b/packages/mcp-server/src/tools/tasks/list-tasks.ts @@ -1,5 +1,7 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +import { asTextContentResult } from 'scan-documents-mcp/tools/types'; + import { Tool } from '@modelcontextprotocol/sdk/types.js'; import type { Metadata } from '../'; import ScanDocuments from 'scan-documents'; @@ -29,9 +31,9 @@ export const tool: Tool = { }, }; -export const handler = (client: ScanDocuments, args: Record | undefined) => { +export const handler = async (client: ScanDocuments, args: Record | undefined) => { const body = args as any; - return client.tasks.list(body); + return asTextContentResult(await client.tasks.list(body)); }; export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/tasks/retrieve-tasks.ts b/packages/mcp-server/src/tools/tasks/retrieve-tasks.ts index a39c2d6..071d89f 100644 --- a/packages/mcp-server/src/tools/tasks/retrieve-tasks.ts +++ b/packages/mcp-server/src/tools/tasks/retrieve-tasks.ts @@ -1,5 +1,7 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +import { asTextContentResult } from 'scan-documents-mcp/tools/types'; + import { Tool } from '@modelcontextprotocol/sdk/types.js'; import type { Metadata } from '../'; import ScanDocuments from 'scan-documents'; @@ -27,9 +29,9 @@ export const tool: Tool = { }, }; -export const handler = (client: ScanDocuments, args: Record | undefined) => { +export const handler = async (client: ScanDocuments, args: Record | undefined) => { const { id, ...body } = args as any; - return client.tasks.retrieve(id); + return asTextContentResult(await client.tasks.retrieve(id)); }; export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/types.ts b/packages/mcp-server/src/tools/types.ts new file mode 100644 index 0000000..182544d --- /dev/null +++ b/packages/mcp-server/src/tools/types.ts @@ -0,0 +1,104 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import ScanDocuments from 'scan-documents'; +import { Tool } from '@modelcontextprotocol/sdk/types.js'; + +type TextContentBlock = { + type: 'text'; + text: string; +}; + +type ImageContentBlock = { + type: 'image'; + data: string; + mimeType: string; +}; + +type AudioContentBlock = { + type: 'audio'; + data: string; + mimeType: string; +}; + +type ResourceContentBlock = { + type: 'resource'; + resource: + | { + uri: string; + mimeType: string; + text: string; + } + | { + uri: string; + mimeType: string; + blob: string; + }; +}; + +export type ContentBlock = TextContentBlock | ImageContentBlock | AudioContentBlock | ResourceContentBlock; + +export type ToolCallResult = { + content: ContentBlock[]; + isError?: boolean; +}; + +export type HandlerFunction = ( + client: ScanDocuments, + args: Record | undefined, +) => Promise; + +export function asTextContentResult(result: Object): ToolCallResult { + return { + content: [ + { + type: 'text', + text: JSON.stringify(result, null, 2), + }, + ], + }; +} + +export async function asBinaryContentResult(response: Response): Promise { + const blob = await response.blob(); + const mimeType = blob.type; + const data = Buffer.from(await blob.arrayBuffer()).toString('base64'); + if (mimeType.startsWith('image/')) { + return { + content: [{ type: 'image', mimeType, data }], + }; + } else if (mimeType.startsWith('audio/')) { + return { + content: [{ type: 'audio', mimeType, data }], + }; + } else { + return { + content: [ + { + type: 'resource', + resource: { + // We must give a URI, even though this isn't actually an MCP resource. + uri: 'resource://tool-response', + mimeType, + blob: data, + }, + }, + ], + }; + } +} + +export type Metadata = { + resource: string; + operation: 'read' | 'write'; + tags: string[]; + + httpMethod?: string; + httpPath?: string; + operationId?: string; +}; + +export type Endpoint = { + metadata: Metadata; + tool: Tool; + handler: HandlerFunction; +}; diff --git a/packages/mcp-server/tests/dynamic-tools.test.ts b/packages/mcp-server/tests/dynamic-tools.test.ts index e2da6bd..08963af 100644 --- a/packages/mcp-server/tests/dynamic-tools.test.ts +++ b/packages/mcp-server/tests/dynamic-tools.test.ts @@ -21,7 +21,8 @@ describe('dynamicTools', () => { describe('list_api_endpoints', () => { it('should return all endpoints when no search query is provided', async () => { - const result = await toolsMap.list_api_endpoints.handler(fakeClient, {}); + const content = await toolsMap.list_api_endpoints.handler(fakeClient, {}); + const result = JSON.parse(content.content[0].text); expect(result.tools).toHaveLength(endpoints.length); expect(result.tools.map((t: { name: string }) => t.name)).toContain('test_read_endpoint'); @@ -31,26 +32,30 @@ describe('dynamicTools', () => { }); it('should filter endpoints by name', async () => { - const result = await toolsMap.list_api_endpoints.handler(fakeClient, { search_query: 'user' }); + const content = await toolsMap.list_api_endpoints.handler(fakeClient, { search_query: 'user' }); + const result = JSON.parse(content.content[0].text); expect(result.tools).toHaveLength(1); expect(result.tools[0].name).toBe('user_endpoint'); }); it('should filter endpoints by resource', async () => { - const result = await toolsMap.list_api_endpoints.handler(fakeClient, { search_query: 'admin' }); + const content = await toolsMap.list_api_endpoints.handler(fakeClient, { search_query: 'admin' }); + const result = JSON.parse(content.content[0].text); expect(result.tools.some((t: { resource: string }) => t.resource === 'admin')).toBeTruthy(); }); it('should filter endpoints by tag', async () => { - const result = await toolsMap.list_api_endpoints.handler(fakeClient, { search_query: 'admin' }); + const content = await toolsMap.list_api_endpoints.handler(fakeClient, { search_query: 'admin' }); + const result = JSON.parse(content.content[0].text); expect(result.tools.some((t: { tags: string[] }) => t.tags.includes('admin'))).toBeTruthy(); }); it('should be case insensitive in search', async () => { - const result = await toolsMap.list_api_endpoints.handler(fakeClient, { search_query: 'ADMIN' }); + const content = await toolsMap.list_api_endpoints.handler(fakeClient, { search_query: 'ADMIN' }); + const result = JSON.parse(content.content[0].text); expect(result.tools.length).toBe(2); result.tools.forEach((tool: { name: string; resource: string; tags: string[] }) => { @@ -63,9 +68,10 @@ describe('dynamicTools', () => { }); it('should filter endpoints by description', async () => { - const result = await toolsMap.list_api_endpoints.handler(fakeClient, { + const content = await toolsMap.list_api_endpoints.handler(fakeClient, { search_query: 'Test endpoint for user_endpoint', }); + const result = JSON.parse(content.content[0].text); expect(result.tools).toHaveLength(1); expect(result.tools[0].name).toBe('user_endpoint'); @@ -73,9 +79,10 @@ describe('dynamicTools', () => { }); it('should filter endpoints by partial description match', async () => { - const result = await toolsMap.list_api_endpoints.handler(fakeClient, { + const content = await toolsMap.list_api_endpoints.handler(fakeClient, { search_query: 'endpoint for user', }); + const result = JSON.parse(content.content[0].text); expect(result.tools).toHaveLength(1); expect(result.tools[0].name).toBe('user_endpoint'); @@ -84,9 +91,10 @@ describe('dynamicTools', () => { describe('get_api_endpoint_schema', () => { it('should return schema for existing endpoint', async () => { - const result = await toolsMap.get_api_endpoint_schema.handler(fakeClient, { + const content = await toolsMap.get_api_endpoint_schema.handler(fakeClient, { endpoint: 'test_read_endpoint', }); + const result = JSON.parse(content.content[0].text); expect(result).toEqual(endpoints[0]?.tool); }); From a140d8fcc3bcd6f1f79e77124283e512bb1ae971 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 7 Jun 2025 03:31:46 +0000 Subject: [PATCH 31/91] chore: avoid type error in certain environments --- src/internal/uploads.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/internal/uploads.ts b/src/internal/uploads.ts index bbf7eab..0b5991e 100644 --- a/src/internal/uploads.ts +++ b/src/internal/uploads.ts @@ -138,7 +138,7 @@ export const createForm = async >( // 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 isNamedBlob = (value: unknown) => value instanceof Blob && 'name' in value; const isUploadable = (value: unknown) => typeof value === 'object' && From 60d76de59fd432ce45d9831e1d8b87c11eec7084 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 11 Jun 2025 02:15:02 +0000 Subject: [PATCH 32/91] chore(mcp): provides high-level initMcpServer function and exports known clients --- packages/mcp-server/package.json | 4 +- packages/mcp-server/src/compat.ts | 40 ++++++++++++++ packages/mcp-server/src/index.ts | 4 +- packages/mcp-server/src/options.ts | 66 +++++------------------ packages/mcp-server/src/server.ts | 53 +++++++++++++----- packages/mcp-server/src/tools/index.ts | 5 +- packages/mcp-server/src/tools/types.ts | 1 - packages/mcp-server/tests/options.test.ts | 9 +--- 8 files changed, 99 insertions(+), 83 deletions(-) diff --git a/packages/mcp-server/package.json b/packages/mcp-server/package.json index bd57562..90b36ef 100644 --- a/packages/mcp-server/package.json +++ b/packages/mcp-server/package.json @@ -28,10 +28,10 @@ }, "dependencies": { "scan-documents": "file:../../dist/", - "@modelcontextprotocol/sdk": "^1.6.1", + "@modelcontextprotocol/sdk": "^1.11.5", "yargs": "^17.7.2", "@cloudflare/cabidela": "^0.2.4", - "zod": "^3.24.4", + "zod": "^3.25.20", "zod-to-json-schema": "^3.24.5" }, "bin": { diff --git a/packages/mcp-server/src/compat.ts b/packages/mcp-server/src/compat.ts index 2cf24a0..ff0d6d4 100644 --- a/packages/mcp-server/src/compat.ts +++ b/packages/mcp-server/src/compat.ts @@ -19,6 +19,46 @@ export const defaultClientCapabilities: ClientCapabilities = { toolNameLength: undefined, }; +export type ClientType = 'openai-agents' | 'claude' | 'claude-code' | 'cursor'; + +// Client presets for compatibility +// Note that these could change over time as models get better, so this is +// a best effort. +export const knownClients: Record = { + 'openai-agents': { + topLevelUnions: false, + validJson: true, + refs: true, + unions: true, + formats: true, + toolNameLength: undefined, + }, + claude: { + topLevelUnions: true, + validJson: false, + refs: true, + unions: true, + formats: true, + toolNameLength: undefined, + }, + 'claude-code': { + topLevelUnions: false, + validJson: true, + refs: true, + unions: true, + formats: true, + toolNameLength: undefined, + }, + cursor: { + topLevelUnions: false, + validJson: true, + refs: false, + unions: false, + formats: false, + toolNameLength: 50, + }, +}; + /** * Attempts to parse strings into JSON objects */ diff --git a/packages/mcp-server/src/index.ts b/packages/mcp-server/src/index.ts index 17e31ce..7704b9b 100644 --- a/packages/mcp-server/src/index.ts +++ b/packages/mcp-server/src/index.ts @@ -1,7 +1,7 @@ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { init, selectTools, server } from './server'; import { Endpoint, endpoints } from './tools'; -import { ParsedOptions, parseOptions } from './options'; +import { McpOptions, parseOptions } from './options'; async function main() { const options = parseOptionsOrError(); @@ -41,7 +41,7 @@ function parseOptionsOrError() { } } -function selectToolsOrError(endpoints: Endpoint[], options: ParsedOptions) { +function selectToolsOrError(endpoints: Endpoint[], options: McpOptions) { try { const includedTools = selectTools(endpoints, options); if (includedTools.length === 0) { diff --git a/packages/mcp-server/src/options.ts b/packages/mcp-server/src/options.ts index 4a2d166..c075101 100644 --- a/packages/mcp-server/src/options.ts +++ b/packages/mcp-server/src/options.ts @@ -1,55 +1,19 @@ import yargs from 'yargs'; import { hideBin } from 'yargs/helpers'; import { endpoints, Filter } from './tools'; -import { ClientCapabilities } from './compat'; +import { ClientCapabilities, knownClients, ClientType } from './compat'; -type ClientType = 'openai-agents' | 'claude' | 'claude-code' | 'cursor'; - -// Client presets for compatibility -// Note that these could change over time as models get better, so this is -// a best effort. -const CLIENT_PRESETS: Record = { - 'openai-agents': { - topLevelUnions: false, - validJson: true, - refs: true, - unions: true, - formats: true, - toolNameLength: undefined, - }, - claude: { - topLevelUnions: true, - validJson: false, - refs: true, - unions: true, - formats: true, - toolNameLength: undefined, - }, - 'claude-code': { - topLevelUnions: false, - validJson: true, - refs: true, - unions: true, - formats: true, - toolNameLength: undefined, - }, - cursor: { - topLevelUnions: false, - validJson: true, - refs: false, - unions: false, - formats: false, - toolNameLength: 50, - }, +export type CLIOptions = McpOptions & { + list: boolean; }; -export interface ParsedOptions { +export type McpOptions = { + client: ClientType | undefined; includeDynamicTools: boolean | undefined; includeAllTools: boolean | undefined; filters: Filter[]; - capabilities: ClientCapabilities; - list: boolean; -} + capabilities?: Partial; +}; const CAPABILITY_CHOICES = [ 'top-level-unions', @@ -80,7 +44,7 @@ function parseCapabilityValue(cap: string): { name: Capability; value?: number } return { name: cap as Capability }; } -export function parseOptions(): ParsedOptions { +export function parseOptions(): CLIOptions { const opts = yargs(hideBin(process.argv)) .option('tools', { type: 'string', @@ -141,7 +105,7 @@ export function parseOptions(): ParsedOptions { }) .option('client', { type: 'string', - choices: Object.keys(CLIENT_PRESETS), + choices: Object.keys(knownClients), description: 'Specify the MCP client being used', }) .option('capability', { @@ -229,14 +193,6 @@ export function parseOptions(): ParsedOptions { toolNameLength: undefined, }; - // Apply client preset if specified - if (typeof argv.client === 'string') { - const clientKey = argv.client as ClientType; - if (CLIENT_PRESETS[clientKey]) { - Object.assign(clientCapabilities, CLIENT_PRESETS[clientKey]); - } - } - // Apply individual capability overrides if (Array.isArray(argv.capability)) { for (const cap of argv.capability) { @@ -282,7 +238,9 @@ export function parseOptions(): ParsedOptions { const includeAllTools = explicitTools ? argv.tools?.includes('all') && !argv.noTools?.includes('all') : undefined; + const client = argv.client as ClientType; return { + client: client && knownClients[client] ? client : undefined, includeDynamicTools, includeAllTools, filters, @@ -323,7 +281,7 @@ Client Presets (--client): Presets like '--client=openai-agents' or '--client=cursor' automatically configure these capabilities based on current known limitations of those clients, simplifying setup. Current presets: -${JSON.stringify(CLIENT_PRESETS, null, 2)} +${JSON.stringify(knownClients, null, 2)} `; } diff --git a/packages/mcp-server/src/server.ts b/packages/mcp-server/src/server.ts index 70f2cb5..72ebf80 100644 --- a/packages/mcp-server/src/server.ts +++ b/packages/mcp-server/src/server.ts @@ -4,15 +4,22 @@ import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { Endpoint, endpoints, HandlerFunction, query } from './tools'; import { CallToolRequestSchema, ListToolsRequestSchema, Tool } from '@modelcontextprotocol/sdk/types.js'; +import { ClientOptions } from 'scan-documents'; import ScanDocuments from 'scan-documents'; import { applyCompatibilityTransformations, ClientCapabilities, defaultClientCapabilities, + knownClients, parseEmbeddedJSON, } from './compat'; import { dynamicTools } from './dynamic-tools'; -import { ParsedOptions } from './options'; +import { McpOptions } from './options'; + +export { McpOptions } from './options'; +export { ClientType } from './compat'; +export { Filter } from './tools'; +export { ClientOptions } from 'scan-documents'; export { endpoints } from './tools'; // Create server instance @@ -32,6 +39,21 @@ export const server = new McpServer( * Initializes the provided MCP Server with the given tools and handlers. * If not provided, the default client, tools and handlers will be used. */ +export function initMcpServer(params: { + server: Server | McpServer; + clientOptions: ClientOptions; + mcpOptions: McpOptions; + endpoints?: { tool: Tool; handler: HandlerFunction }[]; +}) { + const transformedEndpoints = selectTools(endpoints, params.mcpOptions); + const client = new ScanDocuments(params.clientOptions); + const capabilities = { + ...defaultClientCapabilities, + ...(params.mcpOptions.client ? knownClients[params.mcpOptions.client] : params.mcpOptions.capabilities), + }; + init({ server: params.server, client, endpoints: transformedEndpoints, capabilities }); +} + export function init(params: { server: Server | McpServer; client?: ScanDocuments; @@ -65,24 +87,27 @@ export function init(params: { /** * Selects the tools to include in the MCP Server based on the provided options. */ -export function selectTools(endpoints: Endpoint[], options: ParsedOptions) { +export function selectTools(endpoints: Endpoint[], options: McpOptions) { const filteredEndpoints = query(options.filters, endpoints); - const includedTools = filteredEndpoints; + let includedTools = filteredEndpoints; - if (options.includeAllTools && includedTools.length === 0) { - includedTools.push(...endpoints); - } - - if (options.includeDynamicTools) { - includedTools.push(...dynamicTools(endpoints)); - } - - if (includedTools.length === 0) { - includedTools.push(...endpoints); + if (includedTools.length > 0) { + if (options.includeDynamicTools) { + includedTools = dynamicTools(includedTools); + } + } else { + if (options.includeAllTools) { + includedTools = endpoints; + } else if (options.includeDynamicTools) { + includedTools = dynamicTools(endpoints); + } else { + includedTools = endpoints; + } } - return applyCompatibilityTransformations(includedTools, options.capabilities); + const capabilities = { ...defaultClientCapabilities, ...options.capabilities }; + return applyCompatibilityTransformations(includedTools, capabilities); } /** diff --git a/packages/mcp-server/src/tools/index.ts b/packages/mcp-server/src/tools/index.ts index cf4387f..972f773 100644 --- a/packages/mcp-server/src/tools/index.ts +++ b/packages/mcp-server/src/tools/index.ts @@ -70,9 +70,10 @@ export function query(filters: Filter[], endpoints: Endpoint[]): Endpoint[] { }); // Check if any filters didn't match - if (unmatchedFilters.size > 0) { + const unmatched = Array.from(unmatchedFilters).filter((f) => f.type === 'tool' || f.type === 'resource'); + if (unmatched.length > 0) { throw new Error( - `The following filters did not match any endpoints: ${[...unmatchedFilters] + `The following filters did not match any endpoints: ${unmatched .map((f) => `${f.type}=${f.value}`) .join(', ')}`, ); diff --git a/packages/mcp-server/src/tools/types.ts b/packages/mcp-server/src/tools/types.ts index 182544d..d3d1169 100644 --- a/packages/mcp-server/src/tools/types.ts +++ b/packages/mcp-server/src/tools/types.ts @@ -91,7 +91,6 @@ export type Metadata = { resource: string; operation: 'read' | 'write'; tags: string[]; - httpMethod?: string; httpPath?: string; operationId?: string; diff --git a/packages/mcp-server/tests/options.test.ts b/packages/mcp-server/tests/options.test.ts index 9e2b2f8..f7661d6 100644 --- a/packages/mcp-server/tests/options.test.ts +++ b/packages/mcp-server/tests/options.test.ts @@ -77,14 +77,7 @@ describe('parseOptions', () => { const result = parseOptions(); - expect(result.capabilities).toEqual({ - topLevelUnions: false, - validJson: true, - refs: true, - unions: true, - formats: true, - toolNameLength: undefined, - }); + expect(result.client).toEqual('openai-agents'); cleanup(); }); From 354eaa71c3e4e813af7e49c1b00e73ddbfe115e9 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 14 Jun 2025 02:28:22 +0000 Subject: [PATCH 33/91] =?UTF-8?q?fix:=20publish=20script=20=E2=80=94=20han?= =?UTF-8?q?dle=20NPM=20errors=20correctly?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bin/publish-npm | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/bin/publish-npm b/bin/publish-npm index 2505dec..fa2243d 100644 --- a/bin/publish-npm +++ b/bin/publish-npm @@ -7,15 +7,35 @@ npm config set '//registry.npmjs.org/:_authToken' "$NPM_TOKEN" yarn build cd dist +# Get package name and version from package.json +PACKAGE_NAME="$(jq -r -e '.name' ./package.json)" +VERSION="$(jq -r -e '.version' ./package.json)" + # Get latest version from npm # -# If the package doesn't exist, yarn will return -# {"type":"error","data":"Received invalid response from npm."} -# where .data.version doesn't exist so LAST_VERSION will be an empty string. -LAST_VERSION="$(yarn info --json 2> /dev/null | jq -r '.data.version')" - -# Get current version from package.json -VERSION="$(node -p "require('./package.json').version")" +# If the package doesn't exist, npm will return: +# { +# "error": { +# "code": "E404", +# "summary": "Unpublished on 2025-06-05T09:54:53.528Z", +# "detail": "'the_package' is not in this registry..." +# } +# } +NPM_INFO="$(npm view "$PACKAGE_NAME" version --json 2>/dev/null || true)" + +# Check if we got an E404 error +if echo "$NPM_INFO" | jq -e '.error.code == "E404"' > /dev/null 2>&1; then + # Package doesn't exist yet, no last version + LAST_VERSION="" +elif echo "$NPM_INFO" | jq -e '.error' > /dev/null 2>&1; then + # Report other errors + echo "ERROR: npm returned unexpected data:" + echo "$NPM_INFO" + exit 1 +else + # Success - get the version + LAST_VERSION=$(echo "$NPM_INFO" | jq -r '.') # strip quotes +fi # Check if current version is pre-release (e.g. alpha / beta / rc) CURRENT_IS_PRERELEASE=false From 124ef76f37e0c36feb553d0b391581339dc37b12 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 14 Jun 2025 02:42:12 +0000 Subject: [PATCH 34/91] chore(internal): add pure annotations, make base APIResource abstract --- package.json | 2 +- packages/mcp-server/build | 6 +- packages/mcp-server/package.json | 2 +- packages/mcp-server/src/index.ts | 2 + packages/mcp-server/yarn.lock | 162 ++----------------------------- scripts/build | 2 +- src/core/resource.ts | 2 +- src/internal/headers.ts | 10 +- src/internal/uploads.ts | 2 +- src/internal/utils/log.ts | 2 +- src/internal/utils/path.ts | 2 +- src/internal/utils/values.ts | 3 + tsc-multi.json | 12 ++- yarn.lock | 6 +- 14 files changed, 37 insertions(+), 178 deletions(-) diff --git a/package.json b/package.json index 0feff68..754ec46 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "publint": "^0.2.12", "ts-jest": "^29.1.0", "ts-node": "^10.5.0", - "tsc-multi": "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.4/tsc-multi-1.1.4.tgz", + "tsc-multi": "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.7/tsc-multi.tgz", "tsconfig-paths": "^4.0.0", "typescript": "5.8.3" }, diff --git a/packages/mcp-server/build b/packages/mcp-server/build index 146ea13..c9d265f 100644 --- a/packages/mcp-server/build +++ b/packages/mcp-server/build @@ -23,14 +23,10 @@ PKG_JSON_PATH=../../packages/mcp-server/package.json node ../../scripts/utils/ma node scripts/postprocess-dist-package-json.cjs # build to .js/.mjs/.d.ts files -npm exec tsc-multi +./node_modules/.bin/tsc-multi cp tsconfig.dist-src.json dist/src/tsconfig.json -# Add proper Node.js shebang to the top of the file -sed -i.bak '1s;^;#!/usr/bin/env node\n;' dist/index.js -rm dist/index.js.bak - chmod +x dist/index.js DIST_PATH=./dist PKG_IMPORT_PATH=scan-documents-mcp/ node ../../scripts/utils/postprocess-files.cjs diff --git a/packages/mcp-server/package.json b/packages/mcp-server/package.json index 90b36ef..a9486a8 100644 --- a/packages/mcp-server/package.json +++ b/packages/mcp-server/package.json @@ -49,7 +49,7 @@ "ts-jest": "^29.1.0", "ts-morph": "^19.0.0", "ts-node": "^10.5.0", - "tsc-multi": "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.4/tsc-multi-1.1.4.tgz", + "tsc-multi": "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.7/tsc-multi.tgz", "tsconfig-paths": "^4.0.0", "typescript": "5.8.3" }, diff --git a/packages/mcp-server/src/index.ts b/packages/mcp-server/src/index.ts index 7704b9b..0621357 100644 --- a/packages/mcp-server/src/index.ts +++ b/packages/mcp-server/src/index.ts @@ -1,3 +1,5 @@ +#!/usr/bin/env node + import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { init, selectTools, server } from './server'; import { Endpoint, endpoints } from './tools'; diff --git a/packages/mcp-server/yarn.lock b/packages/mcp-server/yarn.lock index 0868204..9970ec3 100644 --- a/packages/mcp-server/yarn.lock +++ b/packages/mcp-server/yarn.lock @@ -742,14 +742,6 @@ expect "^29.0.0" pretty-format "^29.0.0" -"@types/node-fetch@^2.6.4": - version "2.6.12" - resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.12.tgz#8ab5c3ef8330f13100a7479e2cd56d3386830a03" - integrity sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA== - dependencies: - "@types/node" "*" - form-data "^4.0.0" - "@types/node@*": version "22.15.17" resolved "https://registry.yarnpkg.com/@types/node/-/node-22.15.17.tgz#355ccec95f705b664e4332bb64a7f07db30b7055" @@ -757,13 +749,6 @@ dependencies: undici-types "~6.21.0" -"@types/node@^18.11.18": - version "18.19.100" - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.19.100.tgz#7f3aefbb6911099ab7e0902a1f373b1a4d2c1947" - integrity sha512-ojmMP8SZBKprc3qGrGk8Ujpo80AXkrP7G2tOT4VWr5jlr5DHjsJF+emXJz+Wm0glmy4Js62oKMdZZ6B9Y+tEcA== - dependencies: - undici-types "~5.26.4" - "@types/stack-utils@^2.0.0": version "2.0.3" resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.3.tgz#6209321eb2c1712a7e7466422b8cb1fc0d9dd5d8" @@ -867,13 +852,6 @@ resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.3.0.tgz#d06bbb384ebcf6c505fde1c3d0ed4ddffe0aaff8" integrity sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g== -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" - accepts@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/accepts/-/accepts-2.0.0.tgz#bbcf4ba5075467f3f2131eab3cffc73c2f5d7895" @@ -899,13 +877,6 @@ acorn@^8.11.0, acorn@^8.4.1, acorn@^8.9.0: resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.1.tgz#721d5dc10f7d5b5609a891773d47731796935dfb" integrity sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg== -agentkeepalive@^4.2.1: - version "4.6.0" - resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.6.0.tgz#35f73e94b3f40bf65f105219c623ad19c136ea6a" - integrity sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ== - dependencies: - 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" @@ -978,11 +949,6 @@ async@^3.2.3: resolved "https://registry.yarnpkg.com/async/-/async-3.2.6.tgz#1b0728e14929d51b85b449b7f06e27c1145e38ce" integrity sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA== -asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== - babel-jest@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.7.0.tgz#f4369919225b684c56085998ac63dbd05be020d5" @@ -1222,13 +1188,6 @@ 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" - concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" @@ -1318,11 +1277,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== -delayed-stream@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== - depd@2.0.0, depd@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" @@ -1415,16 +1369,6 @@ es-object-atoms@^1.0.0, es-object-atoms@^1.1.1: dependencies: es-errors "^1.3.0" -es-set-tostringtag@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz#f31dbbe0c183b00a6d26eb6325c810c0fd18bd4d" - integrity sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA== - dependencies: - es-errors "^1.3.0" - get-intrinsic "^1.2.6" - has-tostringtag "^1.0.2" - hasown "^2.0.2" - escalade@^3.1.1, escalade@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" @@ -1570,11 +1514,6 @@ etag@^1.8.1: resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== -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== - eventsource-parser@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/eventsource-parser/-/eventsource-parser-3.0.1.tgz#5e358dba9a55ba64ca90da883c4ca35bd82467bd" @@ -1764,29 +1703,6 @@ flatted@^3.2.9: resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.3.tgz#67c8fad95454a7c7abebf74bb78ee74a44023358" integrity sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg== -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@^4.0.0: - version "4.0.2" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.2.tgz#35cabbdd30c3ce73deb2c42d3c8d3ed9ca51794c" - integrity sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.8" - es-set-tostringtag "^2.1.0" - mime-types "^2.1.12" - -formdata-node@^4.3.2: - version "4.4.1" - resolved "https://registry.yarnpkg.com/formdata-node/-/formdata-node-4.4.1.tgz#23f6a5cb9cb55315912cbec4ff7b0f59bbd191e2" - integrity sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ== - dependencies: - node-domexception "1.0.0" - web-streams-polyfill "4.0.0-beta.3" - forwarded@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" @@ -1822,7 +1738,7 @@ get-caller-file@^2.0.5: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== -get-intrinsic@^1.2.5, get-intrinsic@^1.2.6, get-intrinsic@^1.3.0: +get-intrinsic@^1.2.5, get-intrinsic@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01" integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ== @@ -1919,18 +1835,11 @@ has-flag@^4.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== -has-symbols@^1.0.3, has-symbols@^1.1.0: +has-symbols@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338" integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ== -has-tostringtag@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" - integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== - dependencies: - has-symbols "^1.0.3" - hasown@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003" @@ -1959,13 +1868,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== -humanize-ms@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" - integrity sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ== - dependencies: - ms "^2.0.0" - iconv-lite@0.6.3, iconv-lite@^0.6.3: version "0.6.3" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" @@ -2665,23 +2567,11 @@ micromatch@^4.0.4, micromatch@^4.0.8: braces "^3.0.3" picomatch "^2.3.1" -mime-db@1.52.0: - version "1.52.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" - integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== - mime-db@^1.54.0: version "1.54.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.54.0.tgz#cddb3ee4f9c64530dff640236661d42cb6a314f5" integrity sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ== -mime-types@^2.1.12: - version "2.1.35" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" - integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== - dependencies: - mime-db "1.52.0" - mime-types@^3.0.0, mime-types@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-3.0.1.tgz#b1d94d6997a9b32fd69ebaed0db73de8acb519ce" @@ -2732,7 +2622,7 @@ mkdirp@^2.1.6: resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-2.1.6.tgz#964fbcb12b2d8c5d6fbc62a963ac95a273e2cc19" integrity sha512-+hEnITedc8LAtIP9u3HJDFIdcLV2vXP33sqLLIzkv1Db1zO/1OxbvYf0Y1OC/S/Qo5dxHXepofhmxL02PsKe+A== -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== @@ -2747,18 +2637,6 @@ negotiator@^1.0.0: resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-1.0.0.tgz#b6c91bb47172d69f93cfd7c357bbb529019b5f6a" integrity sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg== -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.7.0" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" - integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== - dependencies: - whatwg-url "^5.0.0" - node-int64@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" @@ -3379,11 +3257,6 @@ toidentifier@1.0.1: resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== -tr46@~0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" - integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== - ts-api-utils@^2.0.1: version "2.1.0" resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-2.1.0.tgz#595f7094e46eed364c13fd23e75f9513d29baf91" @@ -3432,9 +3305,9 @@ ts-node@^10.5.0: v8-compile-cache-lib "^3.0.1" yn "3.1.1" -"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" +"tsc-multi@https://github.com/stainless-api/tsc-multi/releases/download/v1.1.7/tsc-multi.tgz": + version "1.1.7" + resolved "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.7/tsc-multi.tgz#52f40adf8b808bd0b633346d11cc4a8aeea465cd" dependencies: debug "^4.3.7" fast-glob "^3.3.2" @@ -3502,11 +3375,6 @@ typescript@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== - undici-types@~6.21.0: version "6.21.0" resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.21.0.tgz#691d00af3909be93a7faa13be61b3a5b50ef12cb" @@ -3563,24 +3431,6 @@ walker@^1.0.8: dependencies: makeerror "1.0.12" -web-streams-polyfill@4.0.0-beta.3: - version "4.0.0-beta.3" - resolved "https://registry.yarnpkg.com/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz#2898486b74f5156095e473efe989dcf185047a38" - integrity sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug== - -webidl-conversions@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" - integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== - -whatwg-url@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" - integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== - 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" diff --git a/scripts/build b/scripts/build index 1414a02..1edc9c7 100755 --- a/scripts/build +++ b/scripts/build @@ -31,7 +31,7 @@ fi node scripts/utils/make-dist-package-json.cjs > dist/package.json # build to .js/.mjs/.d.ts files -npm exec tsc-multi +./node_modules/.bin/tsc-multi # 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 diff --git a/src/core/resource.ts b/src/core/resource.ts index 4762be3..3c20868 100644 --- a/src/core/resource.ts +++ b/src/core/resource.ts @@ -2,7 +2,7 @@ import type { ScanDocuments } from '../client'; -export class APIResource { +export abstract class APIResource { protected _client: ScanDocuments; constructor(client: ScanDocuments) { diff --git a/src/internal/headers.ts b/src/internal/headers.ts index 5cc03ce..c724a9d 100644 --- a/src/internal/headers.ts +++ b/src/internal/headers.ts @@ -1,5 +1,7 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +import { isReadonlyArray } from './utils/values'; + type HeaderValue = string | undefined | null; export type HeadersLike = | Headers @@ -9,7 +11,7 @@ export type HeadersLike = | null | NullableHeaders; -const brand_privateNullableHeaders = Symbol('brand.privateNullableHeaders'); +const brand_privateNullableHeaders = /* @__PURE__ */ Symbol('brand.privateNullableHeaders'); /** * @internal @@ -25,8 +27,6 @@ export type NullableHeaders = { nulls: Set; }; -const isArray = Array.isArray as (val: unknown) => val is readonly unknown[]; - function* iterateHeaders(headers: HeadersLike): IterableIterator { if (!headers) return; @@ -43,7 +43,7 @@ function* iterateHeaders(headers: HeadersLike): IterableIterator; if (headers instanceof Headers) { iter = headers.entries(); - } else if (isArray(headers)) { + } else if (isReadonlyArray(headers)) { iter = headers; } else { shouldClear = true; @@ -52,7 +52,7 @@ function* iterateHeaders(headers: HeadersLike): IterableIterator>(); +const supportsFormDataMap = /** @__PURE__ */ new WeakMap>(); /** * node-fetch doesn't support the global FormData object in recent node versions. Instead of sending diff --git a/src/internal/utils/log.ts b/src/internal/utils/log.ts index 2bae499..c3b661f 100644 --- a/src/internal/utils/log.ts +++ b/src/internal/utils/log.ts @@ -58,7 +58,7 @@ const noopLogger = { debug: noop, }; -let cachedLoggers = new WeakMap(); +let cachedLoggers = /** @__PURE__ */ new WeakMap(); export function loggerFor(client: ScanDocuments): Logger { const logger = client.logger; diff --git a/src/internal/utils/path.ts b/src/internal/utils/path.ts index b56185a..fd17c83 100644 --- a/src/internal/utils/path.ts +++ b/src/internal/utils/path.ts @@ -62,4 +62,4 @@ export const createPathTagFunction = (pathEncoder = encodeURIPath) => /** * URI-encodes path params and ensures no unsafe /./ or /../ path segments are introduced. */ -export const path = createPathTagFunction(encodeURIPath); +export const path = /* @__PURE__ */ createPathTagFunction(encodeURIPath); diff --git a/src/internal/utils/values.ts b/src/internal/utils/values.ts index 7c833c6..084f7a1 100644 --- a/src/internal/utils/values.ts +++ b/src/internal/utils/values.ts @@ -9,6 +9,9 @@ export const isAbsoluteURL = (url: string): boolean => { return startsWithSchemeRegexp.test(url); }; +export let isArray = (val: unknown): val is unknown[] => ((isArray = Array.isArray), isArray(val)); +export let isReadonlyArray = isArray as (val: unknown) => val is readonly unknown[]; + /** 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') { diff --git a/tsc-multi.json b/tsc-multi.json index 170bac7..384ddac 100644 --- a/tsc-multi.json +++ b/tsc-multi.json @@ -1,7 +1,15 @@ { "targets": [ - { "extname": ".js", "module": "commonjs", "shareHelpers": "internal/tslib.js" }, - { "extname": ".mjs", "module": "esnext", "shareHelpers": "internal/tslib.mjs" } + { + "extname": ".js", + "module": "commonjs", + "shareHelpers": "internal/tslib.js" + }, + { + "extname": ".mjs", + "module": "esnext", + "shareHelpers": "internal/tslib.mjs" + } ], "projects": ["tsconfig.build.json"] } diff --git a/yarn.lock b/yarn.lock index 49d3eb8..c611c53 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3283,9 +3283,9 @@ ts-node@^10.5.0: v8-compile-cache-lib "^3.0.0" yn "3.1.1" -"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" +"tsc-multi@https://github.com/stainless-api/tsc-multi/releases/download/v1.1.7/tsc-multi.tgz": + version "1.1.7" + resolved "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.7/tsc-multi.tgz#52f40adf8b808bd0b633346d11cc4a8aeea465cd" dependencies: debug "^4.3.7" fast-glob "^3.3.2" From 880d9dc28bcbcff2b58cca46aca00d0b4e7fe2fe Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 14 Jun 2025 03:09:36 +0000 Subject: [PATCH 35/91] feat(mcp): set X-Stainless-MCP header --- packages/mcp-server/src/server.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/mcp-server/src/server.ts b/packages/mcp-server/src/server.ts index 72ebf80..08b4d7e 100644 --- a/packages/mcp-server/src/server.ts +++ b/packages/mcp-server/src/server.ts @@ -65,7 +65,7 @@ export function init(params: { const endpointMap = Object.fromEntries(providedEndpoints.map((endpoint) => [endpoint.tool.name, endpoint])); - const client = params.client || new ScanDocuments({}); + const client = params.client || new ScanDocuments({ defaultHeaders: { 'X-Stainless-MCP': 'true' } }); server.setRequestHandler(ListToolsRequestSchema, async () => { return { From 8dac14b2973b57895404d1531269ec2a5d3c06ca Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 17 Jun 2025 03:23:12 +0000 Subject: [PATCH 36/91] chore(client): refactor imports --- src/client.ts | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/client.ts b/src/client.ts index 80bfe52..d71b2a4 100644 --- a/src/client.ts +++ b/src/client.ts @@ -5,7 +5,6 @@ import type { HTTPMethod, PromiseOrValue, MergedRequestInit, FinalizedRequestIni 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'; @@ -17,9 +16,6 @@ import * as Errors from './core/error'; 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 { HeadersLike, NullableHeaders, buildHeaders } from './internal/headers'; -import { FinalRequestOptions, RequestOptions } from './internal/request-options'; import { EventListParams, EventListResponse, Events } from './resources/events'; import { File, FileListParams, FileListResponse, FileUploadParams, Files } from './resources/files'; import { @@ -54,8 +50,17 @@ import { Split, } from './resources/pdf-operations'; import { TaskListParams, TaskListResponse, TaskResponse, Tasks } from './resources/tasks'; +import { type Fetch } from './internal/builtin-types'; +import { HeadersLike, NullableHeaders, buildHeaders } from './internal/headers'; +import { FinalRequestOptions, RequestOptions } from './internal/request-options'; import { readEnv } from './internal/utils/env'; -import { formatRequestDetails, loggerFor } from './internal/utils/log'; +import { + type LogLevel, + type Logger, + formatRequestDetails, + loggerFor, + parseLogLevel, +} from './internal/utils/log'; import { isEmptyObj } from './internal/utils/values'; export interface ClientOptions { From 66b4381e898b646f31b5e8cc6b4c298b0ed3c054 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 17 Jun 2025 04:01:19 +0000 Subject: [PATCH 37/91] feat(client): add support for endpoint-specific base URLs --- package.json | 2 +- packages/mcp-server/package.json | 2 +- src/client.ts | 20 ++++++++++++++++---- src/internal/request-options.ts | 1 + tests/index.test.ts | 22 ++++++++++++++++++++++ yarn.lock | 6 +++--- 6 files changed, 44 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index 754ec46..9039fa2 100644 --- a/package.json +++ b/package.json @@ -42,7 +42,7 @@ "publint": "^0.2.12", "ts-jest": "^29.1.0", "ts-node": "^10.5.0", - "tsc-multi": "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.7/tsc-multi.tgz", + "tsc-multi": "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.8/tsc-multi.tgz", "tsconfig-paths": "^4.0.0", "typescript": "5.8.3" }, diff --git a/packages/mcp-server/package.json b/packages/mcp-server/package.json index a9486a8..4ad90c9 100644 --- a/packages/mcp-server/package.json +++ b/packages/mcp-server/package.json @@ -49,7 +49,7 @@ "ts-jest": "^29.1.0", "ts-morph": "^19.0.0", "ts-node": "^10.5.0", - "tsc-multi": "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.7/tsc-multi.tgz", + "tsc-multi": "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.8/tsc-multi.tgz", "tsconfig-paths": "^4.0.0", "typescript": "5.8.3" }, diff --git a/src/client.ts b/src/client.ts index d71b2a4..f3bbd2f 100644 --- a/src/client.ts +++ b/src/client.ts @@ -220,6 +220,13 @@ export class ScanDocuments { }); } + /** + * Check whether the base URL is set to its default. + */ + #baseURLOverridden(): boolean { + return this.baseURL !== 'https://api.scan-documents.com'; + } + protected defaultQuery(): Record | undefined { return this._options.defaultQuery; } @@ -269,11 +276,16 @@ export class ScanDocuments { return Errors.APIError.generate(status, error, message, headers); } - buildURL(path: string, query: Record | null | undefined): string { + buildURL( + path: string, + query: Record | null | undefined, + defaultBaseURL?: string | undefined, + ): string { + const baseURL = (!this.#baseURLOverridden() && defaultBaseURL) || this.baseURL; const url = isAbsoluteURL(path) ? new URL(path) - : new URL(this.baseURL + (this.baseURL.endsWith('/') && path.startsWith('/') ? path.slice(1) : path)); + : new URL(baseURL + (baseURL.endsWith('/') && path.startsWith('/') ? path.slice(1) : path)); const defaultQuery = this.defaultQuery(); if (!isEmptyObj(defaultQuery)) { @@ -614,9 +626,9 @@ export class ScanDocuments { { retryCount = 0 }: { retryCount?: number } = {}, ): { req: FinalizedRequestInit; url: string; timeout: number } { const options = { ...inputOptions }; - const { method, path, query } = options; + const { method, path, query, defaultBaseURL } = options; - const url = this.buildURL(path!, query as Record); + const url = this.buildURL(path!, query as Record, defaultBaseURL); if ('timeout' in options) validatePositiveInteger('timeout', options.timeout); options.timeout = options.timeout ?? this.timeout; const { bodyHeaders, body } = this.buildBody({ options }); diff --git a/src/internal/request-options.ts b/src/internal/request-options.ts index d2ade9e..7de032f 100644 --- a/src/internal/request-options.ts +++ b/src/internal/request-options.ts @@ -20,6 +20,7 @@ export type RequestOptions = { fetchOptions?: MergedRequestInit; signal?: AbortSignal | undefined | null; idempotencyKey?: string; + defaultBaseURL?: string | undefined; __binaryResponse?: boolean | undefined; }; diff --git a/tests/index.test.ts b/tests/index.test.ts index 54da281..92a38ff 100644 --- a/tests/index.test.ts +++ b/tests/index.test.ts @@ -320,6 +320,28 @@ describe('instantiate client', () => { const client = new ScanDocuments({ apiKey: 'My API Key' }); expect(client.baseURL).toEqual('https://api.scan-documents.com'); }); + + test('in request options', () => { + const client = new ScanDocuments({ apiKey: 'My API Key' }); + expect(client.buildURL('/foo', null, 'http://localhost:5000/option')).toEqual( + 'http://localhost:5000/option/foo', + ); + }); + + test('in request options overridden by client options', () => { + const client = new ScanDocuments({ apiKey: 'My API Key', baseURL: 'http://localhost:5000/client' }); + expect(client.buildURL('/foo', null, 'http://localhost:5000/option')).toEqual( + 'http://localhost:5000/client/foo', + ); + }); + + test('in request options overridden by env variable', () => { + process.env['SCAN_DOCUMENTS_BASE_URL'] = 'http://localhost:5000/env'; + const client = new ScanDocuments({ apiKey: 'My API Key' }); + expect(client.buildURL('/foo', null, 'http://localhost:5000/option')).toEqual( + 'http://localhost:5000/env/foo', + ); + }); }); test('maxRetries option is correctly set', () => { diff --git a/yarn.lock b/yarn.lock index c611c53..58c08d5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3283,9 +3283,9 @@ ts-node@^10.5.0: v8-compile-cache-lib "^3.0.0" yn "3.1.1" -"tsc-multi@https://github.com/stainless-api/tsc-multi/releases/download/v1.1.7/tsc-multi.tgz": - version "1.1.7" - resolved "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.7/tsc-multi.tgz#52f40adf8b808bd0b633346d11cc4a8aeea465cd" +"tsc-multi@https://github.com/stainless-api/tsc-multi/releases/download/v1.1.8/tsc-multi.tgz": + version "1.1.8" + resolved "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.8/tsc-multi.tgz#f544b359b8f05e607771ffacc280e58201476b04" dependencies: debug "^4.3.7" fast-glob "^3.3.2" From 006dc41a4a2378ab5f1dffa14a0a317cfa369e9e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 17 Jun 2025 06:46:19 +0000 Subject: [PATCH 38/91] chore(ci): enable for pull requests --- .github/workflows/ci.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9b1b538..81859d0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,6 +7,10 @@ on: - 'integrated/**' - 'stl-preview-head/**' - 'stl-preview-base/**' + pull_request: + branches-ignore: + - 'stl-preview-head/**' + - 'stl-preview-base/**' jobs: lint: From 45a8400be7aeeaa92015119324502c4748c12702 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 18 Jun 2025 02:16:16 +0000 Subject: [PATCH 39/91] chore(readme): update badges --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b30fc51..b9e132e 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Scan Documents TypeScript API Library -[![NPM version](https://img.shields.io/npm/v/scan-documents.svg)](https://npmjs.org/package/scan-documents) ![npm bundle size](https://img.shields.io/bundlephobia/minzip/scan-documents) +[![NPM version]()](https://npmjs.org/package/scan-documents) ![npm bundle size](https://img.shields.io/bundlephobia/minzip/scan-documents) This library provides convenient access to the Scan Documents REST API from server-side TypeScript or JavaScript. From 49d2f241c40a0093938f9c1b70d31541747d20ee Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 19 Jun 2025 04:40:15 +0000 Subject: [PATCH 40/91] chore(readme): use better example snippet for undocumented params --- README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index b9e132e..8cfeec6 100644 --- a/README.md +++ b/README.md @@ -259,9 +259,8 @@ parameter. This library doesn't validate at runtime that the request matches the send will be sent as-is. ```ts -client.foo.create({ - foo: 'my_param', - bar: 12, +client.files.upload({ + // ... // @ts-expect-error baz is not yet public baz: 'undocumented option', }); From da9ed3524a3902f3092e0acd2d0da5edf8be29c2 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 21 Jun 2025 02:19:29 +0000 Subject: [PATCH 41/91] fix(client): explicitly copy fetch in withOptions --- src/client.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/client.ts b/src/client.ts index f3bbd2f..ce47ee9 100644 --- a/src/client.ts +++ b/src/client.ts @@ -214,6 +214,7 @@ export class ScanDocuments { timeout: this.timeout, logger: this.logger, logLevel: this.logLevel, + fetch: this.fetch, fetchOptions: this.fetchOptions, apiKey: this.apiKey, ...options, From ce2dfb1418254f9f68af6beab516b6382fdf1fab Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 24 Jun 2025 04:42:46 +0000 Subject: [PATCH 42/91] refactor(types): replace Record with mapped types --- src/resources/events.ts | 2 +- src/resources/image-operations.ts | 10 +++++----- src/resources/pdf-operations.ts | 8 ++++---- src/resources/shared.ts | 2 +- src/resources/tasks.ts | 18 +++++++++--------- 5 files changed, 20 insertions(+), 20 deletions(-) diff --git a/src/resources/events.ts b/src/resources/events.ts index d48490f..f6bc75f 100644 --- a/src/resources/events.ts +++ b/src/resources/events.ts @@ -584,7 +584,7 @@ export namespace EventListResponse { /** * Additional details about the error */ - details: Record; + details: { [key: string]: unknown }; /** * The error message diff --git a/src/resources/image-operations.ts b/src/resources/image-operations.ts index 5f1345f..8d4227e 100644 --- a/src/resources/image-operations.ts +++ b/src/resources/image-operations.ts @@ -315,7 +315,7 @@ export namespace ApplyEffectResponse { } export interface Result { - details: Record; + details: { [key: string]: unknown }; error: string; } @@ -559,7 +559,7 @@ export namespace ConvertResponse { export namespace FailedConvertTaskResponse { export interface Result { - details: Record; + details: { [key: string]: unknown }; error: string; } @@ -737,7 +737,7 @@ export namespace DetectDocumentsResponse { export namespace FailedConvertTaskResponse { export interface Result { - details: Record; + details: { [key: string]: unknown }; error: string; } @@ -965,7 +965,7 @@ export namespace ExtractTextResponse { export namespace FailedExtractTextTaskResponse { export interface Result { - details: Record; + details: { [key: string]: unknown }; error: string; } @@ -1197,7 +1197,7 @@ export namespace WarpResponse { export namespace FailedWarpTaskResponse { export interface Result { - details: Record; + details: { [key: string]: unknown }; error: string; } diff --git a/src/resources/pdf-operations.ts b/src/resources/pdf-operations.ts index 035c49d..b30328c 100644 --- a/src/resources/pdf-operations.ts +++ b/src/resources/pdf-operations.ts @@ -326,7 +326,7 @@ export namespace ExtractPages { } export interface Result { - details: Record; + details: { [key: string]: unknown }; error: string; } @@ -527,7 +527,7 @@ export namespace Merge { } export interface Result { - details: Record; + details: { [key: string]: unknown }; error: string; } @@ -768,7 +768,7 @@ export namespace Render { } export interface Result { - details: Record; + details: { [key: string]: unknown }; error: string; } @@ -969,7 +969,7 @@ export namespace Split { } export interface Result { - details: Record; + details: { [key: string]: unknown }; error: string; } diff --git a/src/resources/shared.ts b/src/resources/shared.ts index a38034f..39e6ce6 100644 --- a/src/resources/shared.ts +++ b/src/resources/shared.ts @@ -17,7 +17,7 @@ export interface JsonSchemaSpec { */ items?: JsonSchemaSpec; - properties?: Record; + properties?: { [key: string]: JsonSchemaSpec }; required?: Array; diff --git a/src/resources/tasks.ts b/src/resources/tasks.ts index e68f5b0..04130ee 100644 --- a/src/resources/tasks.ts +++ b/src/resources/tasks.ts @@ -272,7 +272,7 @@ export namespace TaskResponse { } export interface Result { - details: Record; + details: { [key: string]: unknown }; error: string; } @@ -410,7 +410,7 @@ export namespace TaskResponse { export namespace FailedConvertTaskResponse { export interface Result { - details: Record; + details: { [key: string]: unknown }; error: string; } @@ -565,7 +565,7 @@ export namespace TaskResponse { export namespace FailedConvertTaskResponse { export interface Result { - details: Record; + details: { [key: string]: unknown }; error: string; } @@ -717,7 +717,7 @@ export namespace TaskResponse { export namespace FailedExtractTextTaskResponse { export interface Result { - details: Record; + details: { [key: string]: unknown }; error: string; } @@ -867,7 +867,7 @@ export namespace TaskResponse { export namespace FailedWarpTaskResponse { export interface Result { - details: Record; + details: { [key: string]: unknown }; error: string; } @@ -1077,7 +1077,7 @@ export namespace TaskResponse { } export interface Result { - details: Record; + details: { [key: string]: unknown }; error: string; } @@ -1267,7 +1267,7 @@ export namespace TaskResponse { } export interface Result { - details: Record; + details: { [key: string]: unknown }; error: string; } @@ -1497,7 +1497,7 @@ export namespace TaskResponse { } export interface Result { - details: Record; + details: { [key: string]: unknown }; error: string; } @@ -1687,7 +1687,7 @@ export namespace TaskResponse { } export interface Result { - details: Record; + details: { [key: string]: unknown }; error: string; } From fcb2b1f3dbfe4c6ba92240cfa24f017fb56f604d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 24 Jun 2025 14:48:04 +0000 Subject: [PATCH 43/91] feat(api): update via SDK Studio --- .stats.yml | 4 +- .../apply-effect-image-operations.ts | 7 +- .../convert-image-operations.ts | 21 +- .../detect-documents-image-operations.ts | 7 +- .../extract-text-image-operations.ts | 28 +- .../image-operations/warp-image-operations.ts | 7 +- .../extract-pages-pdf-operations.ts | 7 +- .../pdf-operations/merge-pdf-operations.ts | 7 +- .../pdf-operations/render-pdf-operations.ts | 7 +- .../pdf-operations/split-pdf-operations.ts | 7 +- src/resources/events.ts | 14 +- src/resources/image-operations.ts | 281 +++++++- src/resources/pdf-operations.ts | 230 ++++++- src/resources/tasks.ts | 637 +++++++++++++++++- tests/api-resources/image-operations.test.ts | 9 +- tests/api-resources/pdf-operations.test.ts | 9 +- 16 files changed, 1207 insertions(+), 75 deletions(-) diff --git a/.stats.yml b/.stats.yml index d65b4ff..5b2cf0d 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 17 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/scan-documents%2Fscan-documents-89170108a4ff25a4120f8723c8c03382b8cc176008e091b90ec26fbd3613b199.yml -openapi_spec_hash: a627d69beb662fa6e8bd9c0ace7bf243 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/scan-documents%2Fscan-documents-42f9aa9c3b2769584f60fa3742f3a004bdf2e3b5ba30a44535b0191654b1a51e.yml +openapi_spec_hash: a0bab3e1411b24d8a662df98d227049a config_hash: 4f1180f734cbc7323ff2ed85a9cd510d diff --git a/packages/mcp-server/src/tools/image-operations/apply-effect-image-operations.ts b/packages/mcp-server/src/tools/image-operations/apply-effect-image-operations.ts index ebe4942..02c917c 100644 --- a/packages/mcp-server/src/tools/image-operations/apply-effect-image-operations.ts +++ b/packages/mcp-server/src/tools/image-operations/apply-effect-image-operations.ts @@ -28,7 +28,12 @@ export const tool: Tool = { }, input: { type: 'string', - description: 'The id of the file to operate on.', + description: 'The id of the file or task to operate on.', + }, + callback_url: { + type: 'string', + description: + 'The URL to call when the task is completed or failed. If you want to receive events, you probably prefer to use `webhooks` instead.', }, name: { type: 'string', diff --git a/packages/mcp-server/src/tools/image-operations/convert-image-operations.ts b/packages/mcp-server/src/tools/image-operations/convert-image-operations.ts index e889a16..f642b09 100644 --- a/packages/mcp-server/src/tools/image-operations/convert-image-operations.ts +++ b/packages/mcp-server/src/tools/image-operations/convert-image-operations.ts @@ -26,13 +26,18 @@ export const tool: Tool = { properties: { input: { type: 'string', - description: 'The id of the file to operate on.', + description: 'The id of the file or task to operate on.', }, target_format: { type: 'string', description: 'The format to convert the image to.', enum: ['image/png'], }, + callback_url: { + type: 'string', + description: + 'The URL to call when the task is completed or failed. If you want to receive events, you probably prefer to use `webhooks` instead.', + }, name: { type: 'string', description: 'The name of the file', @@ -44,7 +49,7 @@ export const tool: Tool = { properties: { input: { type: 'string', - description: 'The id of the file to operate on.', + description: 'The id of the file or task to operate on.', }, quality: { type: 'number', @@ -55,6 +60,11 @@ export const tool: Tool = { description: 'The format to convert the image to.', enum: ['image/jpeg'], }, + callback_url: { + type: 'string', + description: + 'The URL to call when the task is completed or failed. If you want to receive events, you probably prefer to use `webhooks` instead.', + }, name: { type: 'string', description: 'The name of the file', @@ -66,7 +76,7 @@ export const tool: Tool = { properties: { input: { type: 'string', - description: 'The id of the file to operate on.', + description: 'The id of the file or task to operate on.', }, quality: { type: 'number', @@ -77,6 +87,11 @@ export const tool: Tool = { description: 'The format to convert the image to.', enum: ['image/webp'], }, + callback_url: { + type: 'string', + description: + 'The URL to call when the task is completed or failed. If you want to receive events, you probably prefer to use `webhooks` instead.', + }, name: { type: 'string', description: 'The name of the file', diff --git a/packages/mcp-server/src/tools/image-operations/detect-documents-image-operations.ts b/packages/mcp-server/src/tools/image-operations/detect-documents-image-operations.ts index e78a757..905f20f 100644 --- a/packages/mcp-server/src/tools/image-operations/detect-documents-image-operations.ts +++ b/packages/mcp-server/src/tools/image-operations/detect-documents-image-operations.ts @@ -23,7 +23,12 @@ export const tool: Tool = { properties: { input: { type: 'string', - description: 'The id of the file to operate on.', + description: 'The id of the file or task to operate on.', + }, + callback_url: { + type: 'string', + description: + 'The URL to call when the task is completed or failed. If you want to receive events, you probably prefer to use `webhooks` instead.', }, }, }, diff --git a/packages/mcp-server/src/tools/image-operations/extract-text-image-operations.ts b/packages/mcp-server/src/tools/image-operations/extract-text-image-operations.ts index a5d0e9d..2755a04 100644 --- a/packages/mcp-server/src/tools/image-operations/extract-text-image-operations.ts +++ b/packages/mcp-server/src/tools/image-operations/extract-text-image-operations.ts @@ -31,7 +31,12 @@ export const tool: Tool = { }, input: { type: 'string', - description: 'The id of the file to operate on.', + description: 'The id of the file or task to operate on.', + }, + callback_url: { + type: 'string', + description: + 'The URL to call when the task is completed or failed. If you want to receive events, you probably prefer to use `webhooks` instead.', }, }, }, @@ -45,7 +50,12 @@ export const tool: Tool = { }, input: { type: 'string', - description: 'The id of the file to operate on.', + description: 'The id of the file or task to operate on.', + }, + callback_url: { + type: 'string', + description: + 'The URL to call when the task is completed or failed. If you want to receive events, you probably prefer to use `webhooks` instead.', }, }, }, @@ -59,7 +69,12 @@ export const tool: Tool = { }, input: { type: 'string', - description: 'The id of the file to operate on.', + description: 'The id of the file or task to operate on.', + }, + callback_url: { + type: 'string', + description: + 'The URL to call when the task is completed or failed. If you want to receive events, you probably prefer to use `webhooks` instead.', }, }, }, @@ -73,11 +88,16 @@ export const tool: Tool = { }, input: { type: 'string', - description: 'The id of the file to operate on.', + description: 'The id of the file or task to operate on.', }, schema: { $ref: '#/$defs/json_schema_spec', }, + callback_url: { + type: 'string', + description: + 'The URL to call when the task is completed or failed. If you want to receive events, you probably prefer to use `webhooks` instead.', + }, }, }, ], diff --git a/packages/mcp-server/src/tools/image-operations/warp-image-operations.ts b/packages/mcp-server/src/tools/image-operations/warp-image-operations.ts index 5d2552e..90d6c92 100644 --- a/packages/mcp-server/src/tools/image-operations/warp-image-operations.ts +++ b/packages/mcp-server/src/tools/image-operations/warp-image-operations.ts @@ -24,7 +24,7 @@ export const tool: Tool = { properties: { input: { type: 'string', - description: 'The id of the file to operate on.', + description: 'The id of the file or task to operate on.', }, vertices: { type: 'array', @@ -33,6 +33,11 @@ export const tool: Tool = { type: 'object', }, }, + callback_url: { + type: 'string', + description: + 'The URL to call when the task is completed or failed. If you want to receive events, you probably prefer to use `webhooks` instead.', + }, name: { type: 'string', description: 'The name of the file', diff --git a/packages/mcp-server/src/tools/pdf-operations/extract-pages-pdf-operations.ts b/packages/mcp-server/src/tools/pdf-operations/extract-pages-pdf-operations.ts index a45d3ac..bee5b28 100644 --- a/packages/mcp-server/src/tools/pdf-operations/extract-pages-pdf-operations.ts +++ b/packages/mcp-server/src/tools/pdf-operations/extract-pages-pdf-operations.ts @@ -23,12 +23,17 @@ export const tool: Tool = { properties: { input: { type: 'string', - description: 'The id of the file to operate on.', + description: 'The id of the file or task to operate on.', }, pages: { type: 'string', description: 'Page range (e.g., 2-7), a comma-separated list (e.g., 2,3,7) of pages.', }, + callback_url: { + type: 'string', + description: + 'The URL to call when the task is completed or failed. If you want to receive events, you probably prefer to use `webhooks` instead.', + }, name: { type: 'string', description: 'The name of the file', diff --git a/packages/mcp-server/src/tools/pdf-operations/merge-pdf-operations.ts b/packages/mcp-server/src/tools/pdf-operations/merge-pdf-operations.ts index 7cc2adb..2aeeab2 100644 --- a/packages/mcp-server/src/tools/pdf-operations/merge-pdf-operations.ts +++ b/packages/mcp-server/src/tools/pdf-operations/merge-pdf-operations.ts @@ -26,9 +26,14 @@ export const tool: Tool = { description: 'The list of ids of the files to be merged', items: { type: 'string', - description: 'The id of the file to operate on.', + description: 'The id of the file or task to operate on.', }, }, + callback_url: { + type: 'string', + description: + 'The URL to call when the task is completed or failed. If you want to receive events, you probably prefer to use `webhooks` instead.', + }, name: { type: 'string', description: 'The name of the file', diff --git a/packages/mcp-server/src/tools/pdf-operations/render-pdf-operations.ts b/packages/mcp-server/src/tools/pdf-operations/render-pdf-operations.ts index 328cdc4..6629703 100644 --- a/packages/mcp-server/src/tools/pdf-operations/render-pdf-operations.ts +++ b/packages/mcp-server/src/tools/pdf-operations/render-pdf-operations.ts @@ -23,7 +23,12 @@ export const tool: Tool = { properties: { input: { type: 'string', - description: 'The id of the file to operate on.', + description: 'The id of the file or task to operate on.', + }, + callback_url: { + type: 'string', + description: + 'The URL to call when the task is completed or failed. If you want to receive events, you probably prefer to use `webhooks` instead.', }, dpi: { type: 'integer', diff --git a/packages/mcp-server/src/tools/pdf-operations/split-pdf-operations.ts b/packages/mcp-server/src/tools/pdf-operations/split-pdf-operations.ts index 41ec959..89956cd 100644 --- a/packages/mcp-server/src/tools/pdf-operations/split-pdf-operations.ts +++ b/packages/mcp-server/src/tools/pdf-operations/split-pdf-operations.ts @@ -23,7 +23,12 @@ export const tool: Tool = { properties: { input: { type: 'string', - description: 'The id of the file to operate on.', + description: 'The id of the file or task to operate on.', + }, + callback_url: { + type: 'string', + description: + 'The URL to call when the task is completed or failed. If you want to receive events, you probably prefer to use `webhooks` instead.', }, name: { type: 'string', diff --git a/src/resources/events.ts b/src/resources/events.ts index f6bc75f..ef452cd 100644 --- a/src/resources/events.ts +++ b/src/resources/events.ts @@ -237,7 +237,8 @@ export namespace EventListResponse { | 'merge' | 'extract-pages' | 'detect-documents' - | 'apply-effect'; + | 'apply-effect' + | 'scan'; } } @@ -325,6 +326,11 @@ export namespace EventListResponse { */ bounding_box: ImageOperationsAPI.BoundingBox; + /** + * The ID of the file containing the document + */ + file_id: string; + /** * The coordinates of the vertex inside the image */ @@ -523,7 +529,8 @@ export namespace EventListResponse { | 'merge' | 'extract-pages' | 'detect-documents' - | 'apply-effect'; + | 'apply-effect' + | 'scan'; } } @@ -574,7 +581,8 @@ export namespace EventListResponse { | 'merge' | 'extract-pages' | 'detect-documents' - | 'apply-effect'; + | 'apply-effect' + | 'scan'; result: Data.Result; } diff --git a/src/resources/image-operations.ts b/src/resources/image-operations.ts index 8d4227e..f1cfc32 100644 --- a/src/resources/image-operations.ts +++ b/src/resources/image-operations.ts @@ -117,6 +117,11 @@ export namespace ApplyEffectResponse { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -150,10 +155,16 @@ export namespace ApplyEffectResponse { effect: 'grayscale' | 'scanner' | 'black-background'; /** - * The id of the file to operate on. + * The id of the file or task to operate on. */ input: string; + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + /** * The name of the file */ @@ -171,6 +182,11 @@ export namespace ApplyEffectResponse { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -204,10 +220,16 @@ export namespace ApplyEffectResponse { effect: 'grayscale' | 'scanner' | 'black-background'; /** - * The id of the file to operate on. + * The id of the file or task to operate on. */ input: string; + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + /** * The name of the file */ @@ -221,6 +243,11 @@ export namespace ApplyEffectResponse { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -254,10 +281,16 @@ export namespace ApplyEffectResponse { effect: 'grayscale' | 'scanner' | 'black-background'; /** - * The id of the file to operate on. + * The id of the file or task to operate on. */ input: string; + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + /** * The name of the file */ @@ -271,6 +304,11 @@ export namespace ApplyEffectResponse { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -304,10 +342,16 @@ export namespace ApplyEffectResponse { effect: 'grayscale' | 'scanner' | 'black-background'; /** - * The id of the file to operate on. + * The id of the file or task to operate on. */ input: string; + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + /** * The name of the file */ @@ -357,7 +401,7 @@ export type ConvertRequest = export namespace ConvertRequest { export interface PngOptions { /** - * The id of the file to operate on. + * The id of the file or task to operate on. */ input: string; @@ -366,6 +410,12 @@ export namespace ConvertRequest { */ target_format: 'image/png'; + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + /** * The name of the file */ @@ -374,7 +424,7 @@ export namespace ConvertRequest { export interface JpegOptions { /** - * The id of the file to operate on. + * The id of the file or task to operate on. */ input: string; @@ -388,6 +438,12 @@ export namespace ConvertRequest { */ target_format: 'image/jpeg'; + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + /** * The name of the file */ @@ -396,7 +452,7 @@ export namespace ConvertRequest { export interface WebpOptions { /** - * The id of the file to operate on. + * The id of the file or task to operate on. */ input: string; @@ -410,6 +466,12 @@ export namespace ConvertRequest { */ target_format: 'image/webp'; + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + /** * The name of the file */ @@ -433,6 +495,11 @@ export namespace ConvertResponse { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -470,6 +537,11 @@ export namespace ConvertResponse { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -501,6 +573,11 @@ export namespace ConvertResponse { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -532,6 +609,11 @@ export namespace ConvertResponse { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -594,6 +676,11 @@ export namespace DetectDocumentsResponse { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -634,6 +721,11 @@ export namespace DetectDocumentsResponse { */ bounding_box: ImageOperationsAPI.BoundingBox; + /** + * The ID of the file containing the document + */ + file_id: string; + /** * The coordinates of the vertex inside the image */ @@ -648,6 +740,11 @@ export namespace DetectDocumentsResponse { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -679,6 +776,11 @@ export namespace DetectDocumentsResponse { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -710,6 +812,11 @@ export namespace DetectDocumentsResponse { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -761,9 +868,15 @@ export namespace ExtractTextRequest { format: 'plain'; /** - * The id of the file to operate on. + * The id of the file or task to operate on. */ input: string; + + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; } export interface Markdown { @@ -773,9 +886,15 @@ export namespace ExtractTextRequest { format: 'markdown'; /** - * The id of the file to operate on. + * The id of the file or task to operate on. */ input: string; + + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; } export interface HTML { @@ -785,9 +904,15 @@ export namespace ExtractTextRequest { format: 'html'; /** - * The id of the file to operate on. + * The id of the file or task to operate on. */ input: string; + + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; } export interface Json { @@ -797,7 +922,7 @@ export namespace ExtractTextRequest { format: 'json'; /** - * The id of the file to operate on. + * The id of the file or task to operate on. */ input: string; @@ -806,6 +931,12 @@ export namespace ExtractTextRequest { * format is 'json'. */ schema: Shared.JsonSchemaSpec; + + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; } } @@ -825,6 +956,11 @@ export namespace ExtractTextResponse { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -867,6 +1003,11 @@ export namespace ExtractTextResponse { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -901,6 +1042,11 @@ export namespace ExtractTextResponse { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -935,6 +1081,11 @@ export namespace ExtractTextResponse { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -1028,7 +1179,7 @@ export namespace ImageFromTaskResponse { */ export interface WarpRequest { /** - * The id of the file to operate on. + * The id of the file or task to operate on. */ input: string; @@ -1037,6 +1188,12 @@ export interface WarpRequest { */ vertices: Array; + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + /** * The name of the file */ @@ -1059,6 +1216,11 @@ export namespace WarpResponse { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -1099,6 +1261,11 @@ export namespace WarpResponse { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -1133,6 +1300,11 @@ export namespace WarpResponse { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -1167,6 +1339,11 @@ export namespace WarpResponse { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -1211,10 +1388,16 @@ export interface ImageOperationApplyEffectParams { effect: 'grayscale' | 'scanner' | 'black-background'; /** - * The id of the file to operate on. + * The id of the file or task to operate on. */ input: string; + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + /** * The name of the file */ @@ -1229,7 +1412,7 @@ export type ImageOperationConvertParams = export declare namespace ImageOperationConvertParams { export interface PngOptions { /** - * The id of the file to operate on. + * The id of the file or task to operate on. */ input: string; @@ -1238,6 +1421,12 @@ export declare namespace ImageOperationConvertParams { */ target_format: 'image/png'; + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + /** * The name of the file */ @@ -1246,7 +1435,7 @@ export declare namespace ImageOperationConvertParams { export interface JpegOptions { /** - * The id of the file to operate on. + * The id of the file or task to operate on. */ input: string; @@ -1260,6 +1449,12 @@ export declare namespace ImageOperationConvertParams { */ target_format: 'image/jpeg'; + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + /** * The name of the file */ @@ -1268,7 +1463,7 @@ export declare namespace ImageOperationConvertParams { export interface WebpOptions { /** - * The id of the file to operate on. + * The id of the file or task to operate on. */ input: string; @@ -1282,6 +1477,12 @@ export declare namespace ImageOperationConvertParams { */ target_format: 'image/webp'; + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + /** * The name of the file */ @@ -1291,9 +1492,15 @@ export declare namespace ImageOperationConvertParams { export interface ImageOperationDetectDocumentsParams { /** - * The id of the file to operate on. + * The id of the file or task to operate on. */ input: string; + + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; } export type ImageOperationExtractTextParams = @@ -1310,9 +1517,15 @@ export declare namespace ImageOperationExtractTextParams { format: 'plain'; /** - * The id of the file to operate on. + * The id of the file or task to operate on. */ input: string; + + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; } export interface Markdown { @@ -1322,9 +1535,15 @@ export declare namespace ImageOperationExtractTextParams { format: 'markdown'; /** - * The id of the file to operate on. + * The id of the file or task to operate on. */ input: string; + + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; } export interface HTML { @@ -1334,9 +1553,15 @@ export declare namespace ImageOperationExtractTextParams { format: 'html'; /** - * The id of the file to operate on. + * The id of the file or task to operate on. */ input: string; + + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; } export interface Json { @@ -1346,7 +1571,7 @@ export declare namespace ImageOperationExtractTextParams { format: 'json'; /** - * The id of the file to operate on. + * The id of the file or task to operate on. */ input: string; @@ -1355,12 +1580,18 @@ export declare namespace ImageOperationExtractTextParams { * format is 'json'. */ schema: Shared.JsonSchemaSpec; + + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; } } export interface ImageOperationWarpParams { /** - * The id of the file to operate on. + * The id of the file or task to operate on. */ input: string; @@ -1369,6 +1600,12 @@ export interface ImageOperationWarpParams { */ vertices: Array; + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + /** * The name of the file */ diff --git a/src/resources/pdf-operations.ts b/src/resources/pdf-operations.ts index b30328c..37cd311 100644 --- a/src/resources/pdf-operations.ts +++ b/src/resources/pdf-operations.ts @@ -128,6 +128,11 @@ export namespace ExtractPages { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -156,7 +161,7 @@ export namespace ExtractPages { export namespace CompletedExtractPagesTaskResponse { export interface Parameters { /** - * The id of the file to operate on. + * The id of the file or task to operate on. */ input: string; @@ -165,6 +170,12 @@ export namespace ExtractPages { */ pages: string; + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + /** * The name of the file */ @@ -182,6 +193,11 @@ export namespace ExtractPages { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -210,7 +226,7 @@ export namespace ExtractPages { export namespace PendingExtractPagesTaskResponse { export interface Parameters { /** - * The id of the file to operate on. + * The id of the file or task to operate on. */ input: string; @@ -219,6 +235,12 @@ export namespace ExtractPages { */ pages: string; + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + /** * The name of the file */ @@ -232,6 +254,11 @@ export namespace ExtractPages { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -260,7 +287,7 @@ export namespace ExtractPages { export namespace ProcessingExtractPagesTaskResponse { export interface Parameters { /** - * The id of the file to operate on. + * The id of the file or task to operate on. */ input: string; @@ -269,6 +296,12 @@ export namespace ExtractPages { */ pages: string; + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + /** * The name of the file */ @@ -282,6 +315,11 @@ export namespace ExtractPages { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -310,7 +348,7 @@ export namespace ExtractPages { export namespace FailedExtractPagesTaskResponse { export interface Parameters { /** - * The id of the file to operate on. + * The id of the file or task to operate on. */ input: string; @@ -319,6 +357,12 @@ export namespace ExtractPages { */ pages: string; + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + /** * The name of the file */ @@ -349,6 +393,11 @@ export namespace Merge { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -381,6 +430,12 @@ export namespace Merge { */ input: Array; + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + /** * The name of the file */ @@ -398,6 +453,11 @@ export namespace Merge { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -430,6 +490,12 @@ export namespace Merge { */ input: Array; + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + /** * The name of the file */ @@ -443,6 +509,11 @@ export namespace Merge { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -475,6 +546,12 @@ export namespace Merge { */ input: Array; + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + /** * The name of the file */ @@ -488,6 +565,11 @@ export namespace Merge { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -520,6 +602,12 @@ export namespace Merge { */ input: Array; + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + /** * The name of the file */ @@ -550,6 +638,11 @@ export namespace Render { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -583,10 +676,16 @@ export namespace Render { dpi: number; /** - * The id of the file to operate on. + * The id of the file or task to operate on. */ input: string; + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + /** * The name of the file */ @@ -609,6 +708,11 @@ export namespace Render { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -642,10 +746,16 @@ export namespace Render { dpi: number; /** - * The id of the file to operate on. + * The id of the file or task to operate on. */ input: string; + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + /** * The name of the file */ @@ -664,6 +774,11 @@ export namespace Render { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -697,10 +812,16 @@ export namespace Render { dpi: number; /** - * The id of the file to operate on. + * The id of the file or task to operate on. */ input: string; + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + /** * The name of the file */ @@ -719,6 +840,11 @@ export namespace Render { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -752,10 +878,16 @@ export namespace Render { dpi: number; /** - * The id of the file to operate on. + * The id of the file or task to operate on. */ input: string; + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + /** * The name of the file */ @@ -791,6 +923,11 @@ export namespace Split { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -819,10 +956,16 @@ export namespace Split { export namespace CompletedSplitTaskResponse { export interface Parameters { /** - * The id of the file to operate on. + * The id of the file or task to operate on. */ input: string; + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + /** * The name of the file */ @@ -840,6 +983,11 @@ export namespace Split { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -868,10 +1016,16 @@ export namespace Split { export namespace PendingSplitTaskResponse { export interface Parameters { /** - * The id of the file to operate on. + * The id of the file or task to operate on. */ input: string; + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + /** * The name of the file */ @@ -885,6 +1039,11 @@ export namespace Split { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -913,10 +1072,16 @@ export namespace Split { export namespace ProcessingSplitTaskResponse { export interface Parameters { /** - * The id of the file to operate on. + * The id of the file or task to operate on. */ input: string; + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + /** * The name of the file */ @@ -930,6 +1095,11 @@ export namespace Split { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -958,10 +1128,16 @@ export namespace Split { export namespace FailedSplitTaskResponse { export interface Parameters { /** - * The id of the file to operate on. + * The id of the file or task to operate on. */ input: string; + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + /** * The name of the file */ @@ -978,7 +1154,7 @@ export namespace Split { export interface PdfOperationExtractPagesParams { /** - * The id of the file to operate on. + * The id of the file or task to operate on. */ input: string; @@ -987,6 +1163,12 @@ export interface PdfOperationExtractPagesParams { */ pages: string; + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + /** * The name of the file */ @@ -999,6 +1181,12 @@ export interface PdfOperationMergeParams { */ input: Array; + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + /** * The name of the file */ @@ -1007,10 +1195,16 @@ export interface PdfOperationMergeParams { export interface PdfOperationRenderParams { /** - * The id of the file to operate on. + * The id of the file or task to operate on. */ input: string; + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + /** * Dots per inch (DPI) for the rendered image. Default is 300. */ @@ -1029,10 +1223,16 @@ export interface PdfOperationRenderParams { export interface PdfOperationSplitParams { /** - * The id of the file to operate on. + * The id of the file or task to operate on. */ input: string; + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + /** * The name of the file */ diff --git a/src/resources/tasks.ts b/src/resources/tasks.ts index 04130ee..a6e1e0c 100644 --- a/src/resources/tasks.ts +++ b/src/resources/tasks.ts @@ -65,7 +65,11 @@ export type TaskResponse = | TaskResponse.CompletedSplitTaskResponse | TaskResponse.PendingSplitTaskResponse | TaskResponse.ProcessingSplitTaskResponse - | TaskResponse.FailedSplitTaskResponse; + | TaskResponse.FailedSplitTaskResponse + | TaskResponse.CompletedScanTaskResponse + | TaskResponse.PendingScanTaskResponse + | TaskResponse.ProcessingScanTaskResponse + | TaskResponse.FailedScanTaskResponse; export namespace TaskResponse { export interface CompletedApplyEffectTaskResponse { @@ -74,6 +78,11 @@ export namespace TaskResponse { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -107,10 +116,16 @@ export namespace TaskResponse { effect: 'grayscale' | 'scanner' | 'black-background'; /** - * The id of the file to operate on. + * The id of the file or task to operate on. */ input: string; + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + /** * The name of the file */ @@ -128,6 +143,11 @@ export namespace TaskResponse { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -161,10 +181,16 @@ export namespace TaskResponse { effect: 'grayscale' | 'scanner' | 'black-background'; /** - * The id of the file to operate on. + * The id of the file or task to operate on. */ input: string; + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + /** * The name of the file */ @@ -178,6 +204,11 @@ export namespace TaskResponse { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -211,10 +242,16 @@ export namespace TaskResponse { effect: 'grayscale' | 'scanner' | 'black-background'; /** - * The id of the file to operate on. + * The id of the file or task to operate on. */ input: string; + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + /** * The name of the file */ @@ -228,6 +265,11 @@ export namespace TaskResponse { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -261,10 +303,16 @@ export namespace TaskResponse { effect: 'grayscale' | 'scanner' | 'black-background'; /** - * The id of the file to operate on. + * The id of the file or task to operate on. */ input: string; + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + /** * The name of the file */ @@ -284,6 +332,11 @@ export namespace TaskResponse { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -321,6 +374,11 @@ export namespace TaskResponse { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -352,6 +410,11 @@ export namespace TaskResponse { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -383,6 +446,11 @@ export namespace TaskResponse { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -422,6 +490,11 @@ export namespace TaskResponse { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -462,6 +535,11 @@ export namespace TaskResponse { */ bounding_box: ImageOperationsAPI.BoundingBox; + /** + * The ID of the file containing the document + */ + file_id: string; + /** * The coordinates of the vertex inside the image */ @@ -476,6 +554,11 @@ export namespace TaskResponse { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -507,6 +590,11 @@ export namespace TaskResponse { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -538,6 +626,11 @@ export namespace TaskResponse { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -577,6 +670,11 @@ export namespace TaskResponse { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -619,6 +717,11 @@ export namespace TaskResponse { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -653,6 +756,11 @@ export namespace TaskResponse { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -687,6 +795,11 @@ export namespace TaskResponse { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -729,6 +842,11 @@ export namespace TaskResponse { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -769,6 +887,11 @@ export namespace TaskResponse { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -803,6 +926,11 @@ export namespace TaskResponse { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -837,6 +965,11 @@ export namespace TaskResponse { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -879,6 +1012,11 @@ export namespace TaskResponse { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -907,7 +1045,7 @@ export namespace TaskResponse { export namespace CompletedExtractPagesTaskResponse { export interface Parameters { /** - * The id of the file to operate on. + * The id of the file or task to operate on. */ input: string; @@ -916,6 +1054,12 @@ export namespace TaskResponse { */ pages: string; + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + /** * The name of the file */ @@ -933,6 +1077,11 @@ export namespace TaskResponse { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -961,7 +1110,7 @@ export namespace TaskResponse { export namespace PendingExtractPagesTaskResponse { export interface Parameters { /** - * The id of the file to operate on. + * The id of the file or task to operate on. */ input: string; @@ -970,6 +1119,12 @@ export namespace TaskResponse { */ pages: string; + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + /** * The name of the file */ @@ -983,6 +1138,11 @@ export namespace TaskResponse { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -1011,7 +1171,7 @@ export namespace TaskResponse { export namespace ProcessingExtractPagesTaskResponse { export interface Parameters { /** - * The id of the file to operate on. + * The id of the file or task to operate on. */ input: string; @@ -1020,6 +1180,12 @@ export namespace TaskResponse { */ pages: string; + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + /** * The name of the file */ @@ -1033,6 +1199,11 @@ export namespace TaskResponse { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -1061,7 +1232,7 @@ export namespace TaskResponse { export namespace FailedExtractPagesTaskResponse { export interface Parameters { /** - * The id of the file to operate on. + * The id of the file or task to operate on. */ input: string; @@ -1070,6 +1241,12 @@ export namespace TaskResponse { */ pages: string; + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + /** * The name of the file */ @@ -1089,6 +1266,11 @@ export namespace TaskResponse { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -1121,6 +1303,12 @@ export namespace TaskResponse { */ input: Array; + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + /** * The name of the file */ @@ -1138,6 +1326,11 @@ export namespace TaskResponse { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -1170,6 +1363,12 @@ export namespace TaskResponse { */ input: Array; + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + /** * The name of the file */ @@ -1183,6 +1382,11 @@ export namespace TaskResponse { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -1215,6 +1419,12 @@ export namespace TaskResponse { */ input: Array; + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + /** * The name of the file */ @@ -1228,6 +1438,11 @@ export namespace TaskResponse { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -1260,6 +1475,12 @@ export namespace TaskResponse { */ input: Array; + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + /** * The name of the file */ @@ -1279,6 +1500,11 @@ export namespace TaskResponse { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -1312,10 +1538,16 @@ export namespace TaskResponse { dpi: number; /** - * The id of the file to operate on. + * The id of the file or task to operate on. */ input: string; + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + /** * The name of the file */ @@ -1338,6 +1570,11 @@ export namespace TaskResponse { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -1371,10 +1608,16 @@ export namespace TaskResponse { dpi: number; /** - * The id of the file to operate on. + * The id of the file or task to operate on. */ input: string; + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + /** * The name of the file */ @@ -1393,6 +1636,11 @@ export namespace TaskResponse { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -1426,10 +1674,16 @@ export namespace TaskResponse { dpi: number; /** - * The id of the file to operate on. + * The id of the file or task to operate on. */ input: string; + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + /** * The name of the file */ @@ -1448,6 +1702,11 @@ export namespace TaskResponse { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -1481,10 +1740,16 @@ export namespace TaskResponse { dpi: number; /** - * The id of the file to operate on. + * The id of the file or task to operate on. */ input: string; + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + /** * The name of the file */ @@ -1509,6 +1774,11 @@ export namespace TaskResponse { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -1537,10 +1807,16 @@ export namespace TaskResponse { export namespace CompletedSplitTaskResponse { export interface Parameters { /** - * The id of the file to operate on. + * The id of the file or task to operate on. */ input: string; + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + /** * The name of the file */ @@ -1558,6 +1834,11 @@ export namespace TaskResponse { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -1586,10 +1867,16 @@ export namespace TaskResponse { export namespace PendingSplitTaskResponse { export interface Parameters { /** - * The id of the file to operate on. + * The id of the file or task to operate on. */ input: string; + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + /** * The name of the file */ @@ -1603,6 +1890,11 @@ export namespace TaskResponse { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -1631,10 +1923,16 @@ export namespace TaskResponse { export namespace ProcessingSplitTaskResponse { export interface Parameters { /** - * The id of the file to operate on. + * The id of the file or task to operate on. */ input: string; + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + /** * The name of the file */ @@ -1648,6 +1946,11 @@ export namespace TaskResponse { */ id: string; + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + /** * The creation date of the task in ISO format. */ @@ -1676,10 +1979,310 @@ export namespace TaskResponse { export namespace FailedSplitTaskResponse { export interface Parameters { /** - * The id of the file to operate on. + * The id of the file or task to operate on. */ input: string; + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + + /** + * The name of the file + */ + name?: string; + } + + export interface Result { + details: { [key: string]: unknown }; + + error: string; + } + } + + export interface CompletedScanTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'scan'; + + parameters: CompletedScanTaskResponse.Parameters; + + result: CompletedScanTaskResponse.Result; + + /** + * The current status of the task. + */ + status: 'completed'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace CompletedScanTaskResponse { + export interface Parameters { + /** + * The effect to apply to the image + */ + effect: 'none' | 'grayscale' | 'scanner' | 'black-background'; + + /** + * The id of the file or task to operate on. + */ + input: string; + + /** + * Mode for detecting documents in the image. Available modes are: + * + * - **none**: No document detection is performed. + * - **standard**: Using a quick algorithm. Document is detected in the image, and + * the image is cropped to the detected document area fixing the perspective to + * match the document's shape. + */ + scan_mode: 'none' | 'standard'; + + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + + /** + * The name of the file + */ + name?: string; + } + + export interface Result { + generated_files: Array; + } + } + + export interface PendingScanTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'scan'; + + parameters: PendingScanTaskResponse.Parameters; + + result: unknown; + + /** + * The current status of the task. + */ + status: 'pending'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace PendingScanTaskResponse { + export interface Parameters { + /** + * The effect to apply to the image + */ + effect: 'none' | 'grayscale' | 'scanner' | 'black-background'; + + /** + * The id of the file or task to operate on. + */ + input: string; + + /** + * Mode for detecting documents in the image. Available modes are: + * + * - **none**: No document detection is performed. + * - **standard**: Using a quick algorithm. Document is detected in the image, and + * the image is cropped to the detected document area fixing the perspective to + * match the document's shape. + */ + scan_mode: 'none' | 'standard'; + + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + + /** + * The name of the file + */ + name?: string; + } + } + + export interface ProcessingScanTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'scan'; + + parameters: ProcessingScanTaskResponse.Parameters; + + result: unknown; + + /** + * The current status of the task. + */ + status: 'processing'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace ProcessingScanTaskResponse { + export interface Parameters { + /** + * The effect to apply to the image + */ + effect: 'none' | 'grayscale' | 'scanner' | 'black-background'; + + /** + * The id of the file or task to operate on. + */ + input: string; + + /** + * Mode for detecting documents in the image. Available modes are: + * + * - **none**: No document detection is performed. + * - **standard**: Using a quick algorithm. Document is detected in the image, and + * the image is cropped to the detected document area fixing the perspective to + * match the document's shape. + */ + scan_mode: 'none' | 'standard'; + + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + + /** + * The name of the file + */ + name?: string; + } + } + + export interface FailedScanTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'scan'; + + parameters: FailedScanTaskResponse.Parameters; + + result: FailedScanTaskResponse.Result; + + /** + * The current status of the task. + */ + status: 'failed'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace FailedScanTaskResponse { + export interface Parameters { + /** + * The effect to apply to the image + */ + effect: 'none' | 'grayscale' | 'scanner' | 'black-background'; + + /** + * The id of the file or task to operate on. + */ + input: string; + + /** + * Mode for detecting documents in the image. Available modes are: + * + * - **none**: No document detection is performed. + * - **standard**: Using a quick algorithm. Document is detected in the image, and + * the image is cropped to the detected document area fixing the perspective to + * match the document's shape. + */ + scan_mode: 'none' | 'standard'; + + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + /** * The name of the file */ diff --git a/tests/api-resources/image-operations.test.ts b/tests/api-resources/image-operations.test.ts index e8f7113..07957d7 100644 --- a/tests/api-resources/image-operations.test.ts +++ b/tests/api-resources/image-operations.test.ts @@ -28,6 +28,7 @@ describe('resource imageOperations', () => { const response = await client.imageOperations.applyEffect({ effect: 'grayscale', input: 'file_avyrvozb9302uwhq', + callback_url: 'https://example.com/callback', name: 'Example Image', }); }); @@ -52,6 +53,7 @@ describe('resource imageOperations', () => { const response = await client.imageOperations.convert({ input: 'file_avyrvozb9302uwhq', target_format: 'image/png', + callback_url: 'https://example.com/callback', name: 'Example Image', }); }); @@ -70,7 +72,10 @@ describe('resource imageOperations', () => { // skipped: tests are disabled for the time being test.skip('detectDocuments: required and optional params', async () => { - const response = await client.imageOperations.detectDocuments({ input: 'file_avyrvozb9302uwhq' }); + const response = await client.imageOperations.detectDocuments({ + input: 'file_avyrvozb9302uwhq', + callback_url: 'https://example.com/callback', + }); }); // skipped: tests are disabled for the time being @@ -93,6 +98,7 @@ describe('resource imageOperations', () => { const response = await client.imageOperations.extractText({ format: 'plain', input: 'file_avyrvozb9302uwhq', + callback_url: 'https://example.com/callback', }); }); @@ -126,6 +132,7 @@ describe('resource imageOperations', () => { { x: 100, y: 100 }, { x: 0, y: 90 }, ], + callback_url: 'https://example.com/callback', name: 'Example Image', }); }); diff --git a/tests/api-resources/pdf-operations.test.ts b/tests/api-resources/pdf-operations.test.ts index f6d050c..dc39d81 100644 --- a/tests/api-resources/pdf-operations.test.ts +++ b/tests/api-resources/pdf-operations.test.ts @@ -28,6 +28,7 @@ describe('resource pdfOperations', () => { const response = await client.pdfOperations.extractPages({ input: 'file_avyrvozb9302uwhq', pages: '2-7', + callback_url: 'https://example.com/callback', name: 'File Name', }); }); @@ -48,6 +49,7 @@ describe('resource pdfOperations', () => { test.skip('merge: required and optional params', async () => { const response = await client.pdfOperations.merge({ input: ['file_avyrvozb9302uwhq'], + callback_url: 'https://example.com/callback', name: 'File Name', }); }); @@ -68,6 +70,7 @@ describe('resource pdfOperations', () => { test.skip('render: required and optional params', async () => { const response = await client.pdfOperations.render({ input: 'file_avyrvozb9302uwhq', + callback_url: 'https://example.com/callback', dpi: 300, name: 'File Name', pages: '2-7', @@ -88,6 +91,10 @@ describe('resource pdfOperations', () => { // skipped: tests are disabled for the time being test.skip('split: required and optional params', async () => { - const response = await client.pdfOperations.split({ input: 'file_avyrvozb9302uwhq', name: 'File Name' }); + const response = await client.pdfOperations.split({ + input: 'file_avyrvozb9302uwhq', + callback_url: 'https://example.com/callback', + name: 'File Name', + }); }); }); From 29066c78a803d4eb260385bdf2a3e7748390b91d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 24 Jun 2025 15:05:16 +0000 Subject: [PATCH 44/91] feat(api): update via SDK Studio --- .stats.yml | 4 +- api.md | 2 + packages/mcp-server/README.md | 2 + .../image-operations/scan-image-operations.ts | 58 +++ packages/mcp-server/src/tools/index.ts | 2 + src/client.ts | 4 + src/resources/image-operations.ts | 358 ++++++++++++++++++ src/resources/index.ts | 2 + tests/api-resources/image-operations.test.ts | 27 ++ 9 files changed, 457 insertions(+), 2 deletions(-) create mode 100644 packages/mcp-server/src/tools/image-operations/scan-image-operations.ts diff --git a/.stats.yml b/.stats.yml index 5b2cf0d..0d3cbbe 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 17 +configured_endpoints: 18 openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/scan-documents%2Fscan-documents-42f9aa9c3b2769584f60fa3742f3a004bdf2e3b5ba30a44535b0191654b1a51e.yml openapi_spec_hash: a0bab3e1411b24d8a662df98d227049a -config_hash: 4f1180f734cbc7323ff2ed85a9cd510d +config_hash: c1dd12e2ddf127e74f1b4981eef49e2b diff --git a/api.md b/api.md index 1984514..d1640a6 100644 --- a/api.md +++ b/api.md @@ -54,6 +54,7 @@ Types: - ExtractTextRequest - ExtractTextResponse - ImageFromTaskResponse +- ScanResponse - WarpRequest - WarpResponse @@ -63,6 +64,7 @@ Methods: - client.imageOperations.convert({ ...params }) -> ConvertResponse - client.imageOperations.detectDocuments({ ...params }) -> DetectDocumentsResponse - client.imageOperations.extractText({ ...params }) -> ExtractTextResponse +- client.imageOperations.scan({ ...params }) -> ScanResponse - client.imageOperations.warp({ ...params }) -> WarpResponse # PdfOperations diff --git a/packages/mcp-server/README.md b/packages/mcp-server/README.md index f36e13c..0e6cc64 100644 --- a/packages/mcp-server/README.md +++ b/packages/mcp-server/README.md @@ -188,6 +188,8 @@ The following tools are available in this MCP server. - `convert_image_operations` (`write`): Creates a task to convert an image file to a different format. - `detect_documents_image_operations` (`write`): Creates a task to detect document boundaries within an image. - `extract_text_image_operations` (`write`): Creates a task to extract text from a specified image file. +- `scan_image_operations` (`write`): Creates a task to scan an image file. + This is an equivalent operation for `detect-documents` and `warp` combined, additionally it can apply effects to the scanned image. - `warp_image_operations` (`write`): Creates a task to apply perspective correction (warp) to an image based on detected document boundaries. ### Resource `pdf_operations`: diff --git a/packages/mcp-server/src/tools/image-operations/scan-image-operations.ts b/packages/mcp-server/src/tools/image-operations/scan-image-operations.ts new file mode 100644 index 0000000..108d4fb --- /dev/null +++ b/packages/mcp-server/src/tools/image-operations/scan-image-operations.ts @@ -0,0 +1,58 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { asTextContentResult } from 'scan-documents-mcp/tools/types'; + +import { Tool } from '@modelcontextprotocol/sdk/types.js'; +import type { Metadata } from '../'; +import ScanDocuments from 'scan-documents'; + +export const metadata: Metadata = { + resource: 'image_operations', + operation: 'write', + tags: [], + httpMethod: 'post', + httpPath: '/v1/image-operations/scan', + operationId: 'scanImage', +}; + +export const tool: Tool = { + name: 'scan_image_operations', + description: + 'Creates a task to scan an image file. \nThis is an equivalent operation for `detect-documents` and `warp` combined, additionally it can apply effects to the scanned image.', + inputSchema: { + type: 'object', + properties: { + effect: { + type: 'string', + description: 'The effect to apply to the image', + enum: ['none', 'grayscale', 'scanner', 'black-background'], + }, + input: { + type: 'string', + description: 'The id of the file or task to operate on.', + }, + scan_mode: { + type: 'string', + description: + "Mode for detecting documents in the image. Available modes are:\n- **none**: No document detection is performed.\n- **standard**: Using a quick algorithm. Document is detected in the image, and the image is cropped to the detected document area fixing the perspective to match the document's shape.", + enum: ['none', 'standard'], + }, + callback_url: { + type: 'string', + description: + 'The URL to call when the task is completed or failed. If you want to receive events, you probably prefer to use `webhooks` instead.', + }, + name: { + type: 'string', + description: 'The name of the file', + }, + }, + }, +}; + +export const handler = async (client: ScanDocuments, args: Record | undefined) => { + const body = args as any; + return asTextContentResult(await client.imageOperations.scan(body)); +}; + +export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/index.ts b/packages/mcp-server/src/tools/index.ts index 972f773..f862226 100644 --- a/packages/mcp-server/src/tools/index.ts +++ b/packages/mcp-server/src/tools/index.ts @@ -16,6 +16,7 @@ import apply_effect_image_operations from './image-operations/apply-effect-image import convert_image_operations from './image-operations/convert-image-operations'; import detect_documents_image_operations from './image-operations/detect-documents-image-operations'; import extract_text_image_operations from './image-operations/extract-text-image-operations'; +import scan_image_operations from './image-operations/scan-image-operations'; import warp_image_operations from './image-operations/warp-image-operations'; import extract_pages_pdf_operations from './pdf-operations/extract-pages-pdf-operations'; import merge_pdf_operations from './pdf-operations/merge-pdf-operations'; @@ -40,6 +41,7 @@ addEndpoint(apply_effect_image_operations); addEndpoint(convert_image_operations); addEndpoint(detect_documents_image_operations); addEndpoint(extract_text_image_operations); +addEndpoint(scan_image_operations); addEndpoint(warp_image_operations); addEndpoint(extract_pages_pdf_operations); addEndpoint(merge_pdf_operations); diff --git a/src/client.ts b/src/client.ts index ce47ee9..7370a77 100644 --- a/src/client.ts +++ b/src/client.ts @@ -32,8 +32,10 @@ import { ImageOperationConvertParams, ImageOperationDetectDocumentsParams, ImageOperationExtractTextParams, + ImageOperationScanParams, ImageOperationWarpParams, ImageOperations, + ScanResponse, WarpRequest, WarpResponse, } from './resources/image-operations'; @@ -788,12 +790,14 @@ export declare namespace ScanDocuments { type ExtractTextRequest as ExtractTextRequest, type ExtractTextResponse as ExtractTextResponse, type ImageFromTaskResponse as ImageFromTaskResponse, + type ScanResponse as ScanResponse, type WarpRequest as WarpRequest, type WarpResponse as WarpResponse, type ImageOperationApplyEffectParams as ImageOperationApplyEffectParams, type ImageOperationConvertParams as ImageOperationConvertParams, type ImageOperationDetectDocumentsParams as ImageOperationDetectDocumentsParams, type ImageOperationExtractTextParams as ImageOperationExtractTextParams, + type ImageOperationScanParams as ImageOperationScanParams, type ImageOperationWarpParams as ImageOperationWarpParams, }; diff --git a/src/resources/image-operations.ts b/src/resources/image-operations.ts index f1cfc32..099a24c 100644 --- a/src/resources/image-operations.ts +++ b/src/resources/image-operations.ts @@ -79,6 +79,24 @@ export class ImageOperations extends APIResource { return this._client.post('/v1/image-operations/extract-text', { body, ...options }); } + /** + * Creates a task to scan an image file. This is an equivalent operation for + * `detect-documents` and `warp` combined, additionally it can apply effects to the + * scanned image. + * + * @example + * ```ts + * const scanResponse = await client.imageOperations.scan({ + * effect: 'none', + * input: 'file_avyrvozb9302uwhq', + * scan_mode: 'standard', + * }); + * ``` + */ + scan(body: ImageOperationScanParams, options?: RequestOptions): APIPromise { + return this._client.post('/v1/image-operations/scan', { body, ...options }); + } + /** * Creates a task to apply perspective correction (warp) to an image based on * detected document boundaries. @@ -1174,6 +1192,311 @@ export namespace ImageFromTaskResponse { } } +/** + * The response of an scan task + */ +export type ScanResponse = + | ScanResponse.CompletedScanTaskResponse + | ScanResponse.PendingScanTaskResponse + | ScanResponse.ProcessingScanTaskResponse + | ScanResponse.FailedScanTaskResponse; + +export namespace ScanResponse { + export interface CompletedScanTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'scan'; + + parameters: CompletedScanTaskResponse.Parameters; + + result: CompletedScanTaskResponse.Result; + + /** + * The current status of the task. + */ + status: 'completed'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace CompletedScanTaskResponse { + export interface Parameters { + /** + * The effect to apply to the image + */ + effect: 'none' | 'grayscale' | 'scanner' | 'black-background'; + + /** + * The id of the file or task to operate on. + */ + input: string; + + /** + * Mode for detecting documents in the image. Available modes are: + * + * - **none**: No document detection is performed. + * - **standard**: Using a quick algorithm. Document is detected in the image, and + * the image is cropped to the detected document area fixing the perspective to + * match the document's shape. + */ + scan_mode: 'none' | 'standard'; + + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + + /** + * The name of the file + */ + name?: string; + } + + export interface Result { + generated_files: Array; + } + } + + export interface PendingScanTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'scan'; + + parameters: PendingScanTaskResponse.Parameters; + + result: unknown; + + /** + * The current status of the task. + */ + status: 'pending'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace PendingScanTaskResponse { + export interface Parameters { + /** + * The effect to apply to the image + */ + effect: 'none' | 'grayscale' | 'scanner' | 'black-background'; + + /** + * The id of the file or task to operate on. + */ + input: string; + + /** + * Mode for detecting documents in the image. Available modes are: + * + * - **none**: No document detection is performed. + * - **standard**: Using a quick algorithm. Document is detected in the image, and + * the image is cropped to the detected document area fixing the perspective to + * match the document's shape. + */ + scan_mode: 'none' | 'standard'; + + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + + /** + * The name of the file + */ + name?: string; + } + } + + export interface ProcessingScanTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'scan'; + + parameters: ProcessingScanTaskResponse.Parameters; + + result: unknown; + + /** + * The current status of the task. + */ + status: 'processing'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace ProcessingScanTaskResponse { + export interface Parameters { + /** + * The effect to apply to the image + */ + effect: 'none' | 'grayscale' | 'scanner' | 'black-background'; + + /** + * The id of the file or task to operate on. + */ + input: string; + + /** + * Mode for detecting documents in the image. Available modes are: + * + * - **none**: No document detection is performed. + * - **standard**: Using a quick algorithm. Document is detected in the image, and + * the image is cropped to the detected document area fixing the perspective to + * match the document's shape. + */ + scan_mode: 'none' | 'standard'; + + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + + /** + * The name of the file + */ + name?: string; + } + } + + export interface FailedScanTaskResponse { + /** + * The unique identifier for the task. + */ + id: string; + + /** + * The URL to which the task result will be sent upon completion or failure. + */ + callback_url: string | null; + + /** + * The creation date of the task in ISO format. + */ + created_at: string; + + /** + * The type of operation being performed by the task. + */ + operation: 'scan'; + + parameters: FailedScanTaskResponse.Parameters; + + result: FailedScanTaskResponse.Result; + + /** + * The current status of the task. + */ + status: 'failed'; + + /** + * The last update date of the task in ISO format. + */ + updated_at: string; + } + + export namespace FailedScanTaskResponse { + export interface Parameters { + /** + * The effect to apply to the image + */ + effect: 'none' | 'grayscale' | 'scanner' | 'black-background'; + + /** + * The id of the file or task to operate on. + */ + input: string; + + /** + * Mode for detecting documents in the image. Available modes are: + * + * - **none**: No document detection is performed. + * - **standard**: Using a quick algorithm. Document is detected in the image, and + * the image is cropped to the detected document area fixing the perspective to + * match the document's shape. + */ + scan_mode: 'none' | 'standard'; + + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + + /** + * The name of the file + */ + name?: string; + } + + export interface Result { + details: { [key: string]: unknown }; + + error: string; + } + } +} + /** * Transform an image by warping it to a quadrilateral. */ @@ -1589,6 +1912,39 @@ export declare namespace ImageOperationExtractTextParams { } } +export interface ImageOperationScanParams { + /** + * The effect to apply to the image + */ + effect: 'none' | 'grayscale' | 'scanner' | 'black-background'; + + /** + * The id of the file or task to operate on. + */ + input: string; + + /** + * Mode for detecting documents in the image. Available modes are: + * + * - **none**: No document detection is performed. + * - **standard**: Using a quick algorithm. Document is detected in the image, and + * the image is cropped to the detected document area fixing the perspective to + * match the document's shape. + */ + scan_mode: 'none' | 'standard'; + + /** + * The URL to call when the task is completed or failed. If you want to receive + * events, you probably prefer to use `webhooks` instead. + */ + callback_url?: string; + + /** + * The name of the file + */ + name?: string; +} + export interface ImageOperationWarpParams { /** * The id of the file or task to operate on. @@ -1623,12 +1979,14 @@ export declare namespace ImageOperations { type ExtractTextRequest as ExtractTextRequest, type ExtractTextResponse as ExtractTextResponse, type ImageFromTaskResponse as ImageFromTaskResponse, + type ScanResponse as ScanResponse, type WarpRequest as WarpRequest, type WarpResponse as WarpResponse, type ImageOperationApplyEffectParams as ImageOperationApplyEffectParams, type ImageOperationConvertParams as ImageOperationConvertParams, type ImageOperationDetectDocumentsParams as ImageOperationDetectDocumentsParams, type ImageOperationExtractTextParams as ImageOperationExtractTextParams, + type ImageOperationScanParams as ImageOperationScanParams, type ImageOperationWarpParams as ImageOperationWarpParams, }; } diff --git a/src/resources/index.ts b/src/resources/index.ts index d5e18da..0fe535d 100644 --- a/src/resources/index.ts +++ b/src/resources/index.ts @@ -14,12 +14,14 @@ export { type ExtractTextRequest, type ExtractTextResponse, type ImageFromTaskResponse, + type ScanResponse, type WarpRequest, type WarpResponse, type ImageOperationApplyEffectParams, type ImageOperationConvertParams, type ImageOperationDetectDocumentsParams, type ImageOperationExtractTextParams, + type ImageOperationScanParams, type ImageOperationWarpParams, } from './image-operations'; export { diff --git a/tests/api-resources/image-operations.test.ts b/tests/api-resources/image-operations.test.ts index 07957d7..b0fafc0 100644 --- a/tests/api-resources/image-operations.test.ts +++ b/tests/api-resources/image-operations.test.ts @@ -102,6 +102,33 @@ describe('resource imageOperations', () => { }); }); + // skipped: tests are disabled for the time being + test.skip('scan: only required params', async () => { + const responsePromise = client.imageOperations.scan({ + effect: 'none', + input: 'file_avyrvozb9302uwhq', + scan_mode: 'standard', + }); + 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); + }); + + // skipped: tests are disabled for the time being + test.skip('scan: required and optional params', async () => { + const response = await client.imageOperations.scan({ + effect: 'none', + input: 'file_avyrvozb9302uwhq', + scan_mode: 'standard', + callback_url: 'https://example.com/callback', + name: 'Example Image', + }); + }); + // skipped: tests are disabled for the time being test.skip('warp: only required params', async () => { const responsePromise = client.imageOperations.warp({ From 2430747fe786df1a9e237b884c59082cfc21a2bf Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 27 Jun 2025 02:37:50 +0000 Subject: [PATCH 45/91] =?UTF-8?q?fix(ci):=20release-doctor=20=E2=80=94=20r?= =?UTF-8?q?eport=20correct=20token=20name?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bin/check-release-environment | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/check-release-environment b/bin/check-release-environment index d3cfc3d..e4b6d58 100644 --- a/bin/check-release-environment +++ b/bin/check-release-environment @@ -3,7 +3,7 @@ errors=() if [ -z "${NPM_TOKEN}" ]; then - errors+=("The SCAN_DOCUMENTS_NPM_TOKEN secret has not been set. Please set it in either this repository's secrets or your organization secrets") + errors+=("The NPM_TOKEN secret has not been set. Please set it in either this repository's secrets or your organization secrets") fi lenErrors=${#errors[@]} From 0a17458ddfe37d5b3e5c10f7e257fad3e2d08129 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 27 Jun 2025 05:57:13 +0000 Subject: [PATCH 46/91] fix(client): get fetchOptions type more reliably --- src/internal/types.ts | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/src/internal/types.ts b/src/internal/types.ts index d7928cd..b668dfc 100644 --- a/src/internal/types.ts +++ b/src/internal/types.ts @@ -7,7 +7,7 @@ export type KeysEnum = { [P in keyof Required]: true }; export type FinalizedRequestInit = RequestInit & { headers: Headers }; -type NotAny = [unknown] extends [T] ? never : T; +type NotAny = [0] extends [1 & T] ? never : T; /** * Some environments overload the global fetch function, and Parameters only gets the last signature. @@ -64,13 +64,15 @@ type OverloadedParameters = * [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; +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; +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 with node-fetch@2 */ +type NodeFetch2RequestInit = NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny; +/** @ts-ignore For users with node-fetch@3, doesn't need file extension because types are at ./@types/index.d.ts */ +type NodeFetch3RequestInit = NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny; /** @ts-ignore For users who use Deno */ type FetchRequestInit = NonNullable[1]>; /* eslint-enable */ @@ -79,7 +81,8 @@ type RequestInits = | NotAny | NotAny | NotAny - | NotAny + | NotAny + | NotAny | NotAny | NotAny; From 965b6064ff025b992e21c9fd54edbe6963d27b6b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 28 Jun 2025 02:57:52 +0000 Subject: [PATCH 47/91] feat(mcp): fallback for void-typed methods --- packages/mcp-server/src/tools/files/delete-files.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/mcp-server/src/tools/files/delete-files.ts b/packages/mcp-server/src/tools/files/delete-files.ts index 55141de..744d26d 100644 --- a/packages/mcp-server/src/tools/files/delete-files.ts +++ b/packages/mcp-server/src/tools/files/delete-files.ts @@ -30,8 +30,8 @@ export const tool: Tool = { export const handler = async (client: ScanDocuments, args: Record | undefined) => { const { id, ...body } = args as any; - await client.files.delete(id); - return asTextContentResult('Successful tool call'); + const response = await client.files.delete(id).asResponse(); + return asTextContentResult(await response.text()); }; export default { metadata, tool, handler }; From fedf819df77819d08582e26bf2d768a0971684d0 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 28 Jun 2025 08:36:39 +0000 Subject: [PATCH 48/91] chore(ci): only run for pushes and fork pull requests --- .github/workflows/ci.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 81859d0..0e2457d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,6 +17,7 @@ jobs: timeout-minutes: 10 name: lint runs-on: ${{ github.repository == 'stainless-sdks/scan-documents-typescript' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} + if: github.event_name == 'push' || github.event.pull_request.head.repo.fork steps: - uses: actions/checkout@v4 @@ -35,6 +36,7 @@ jobs: timeout-minutes: 5 name: build runs-on: ${{ github.repository == 'stainless-sdks/scan-documents-typescript' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} + if: github.event_name == 'push' || github.event.pull_request.head.repo.fork permissions: contents: read id-token: write @@ -70,6 +72,7 @@ jobs: timeout-minutes: 10 name: test runs-on: ${{ github.repository == 'stainless-sdks/scan-documents-typescript' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} + if: github.event_name == 'push' || github.event.pull_request.head.repo.fork steps: - uses: actions/checkout@v4 From 00bb1237344ad7b4d3cafb5ee3f8015033f581ad Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 1 Jul 2025 02:15:36 +0000 Subject: [PATCH 49/91] chore(client): improve path param validation --- src/internal/uploads.ts | 2 +- src/internal/utils/log.ts | 2 +- src/internal/utils/path.ts | 37 +++++++-- tests/path.test.ts | 158 +++++++++++++++++++++++++++++++++++-- 4 files changed, 183 insertions(+), 16 deletions(-) diff --git a/src/internal/uploads.ts b/src/internal/uploads.ts index ce181b0..3f8d966 100644 --- a/src/internal/uploads.ts +++ b/src/internal/uploads.ts @@ -90,7 +90,7 @@ export const multipartFormRequestOptions = async ( return { ...opts, body: await createForm(opts.body, fetch) }; }; -const supportsFormDataMap = /** @__PURE__ */ new WeakMap>(); +const supportsFormDataMap = /* @__PURE__ */ new WeakMap>(); /** * node-fetch doesn't support the global FormData object in recent node versions. Instead of sending diff --git a/src/internal/utils/log.ts b/src/internal/utils/log.ts index c3b661f..1eac140 100644 --- a/src/internal/utils/log.ts +++ b/src/internal/utils/log.ts @@ -58,7 +58,7 @@ const noopLogger = { debug: noop, }; -let cachedLoggers = /** @__PURE__ */ new WeakMap(); +let cachedLoggers = /* @__PURE__ */ new WeakMap(); export function loggerFor(client: ScanDocuments): Logger { const logger = client.logger; diff --git a/src/internal/utils/path.ts b/src/internal/utils/path.ts index fd17c83..ae6b727 100644 --- a/src/internal/utils/path.ts +++ b/src/internal/utils/path.ts @@ -12,25 +12,43 @@ export function encodeURIPath(str: string) { return str.replace(/[^A-Za-z0-9\-._~!$&'()*+,;=:@]+/g, encodeURIComponent); } +const EMPTY = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.create(null)); + 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 invalidSegments = []; 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 value = params[index]; + let encoded = (postPath ? encodeURIComponent : pathEncoder)('' + value); + if ( + index !== params.length && + (value == null || + (typeof value === 'object' && + // handle values from other realms + value.toString === + Object.getPrototypeOf(Object.getPrototypeOf((value as any).hasOwnProperty ?? EMPTY) ?? EMPTY) + ?.toString)) + ) { + encoded = value + ''; + invalidSegments.push({ + start: previousValue.length + currentValue.length, + length: encoded.length, + error: `Value of type ${Object.prototype.toString + .call(value) + .slice(8, -1)} is not a valid path parameter`, + }); + } + return previousValue + currentValue + (index === params.length ? '' : encoded); }, ''); const pathOnly = path.split(/[?#]/, 1)[0]!; - const invalidSegments = []; const invalidSegmentPattern = /(?<=^|\/)(?:\.|%2e){1,2}(?=\/|$)/gi; let match; @@ -39,9 +57,12 @@ export const createPathTagFunction = (pathEncoder = encodeURIPath) => invalidSegments.push({ start: match.index, length: match[0].length, + error: `Value "${match[0]}" can\'t be safely passed as a path parameter`, }); } + invalidSegments.sort((a, b) => a.start - b.start); + if (invalidSegments.length > 0) { let lastEnd = 0; const underline = invalidSegments.reduce((acc, segment) => { @@ -52,7 +73,9 @@ export const createPathTagFunction = (pathEncoder = encodeURIPath) => }, ''); throw new ScanDocumentsError( - `Path parameters result in path with invalid segments:\n${path}\n${underline}`, + `Path parameters result in path with invalid segments:\n${invalidSegments + .map((e) => e.error) + .join('\n')}\n${path}\n${underline}`, ); } diff --git a/tests/path.test.ts b/tests/path.test.ts index 096bc58..15eb7d4 100644 --- a/tests/path.test.ts +++ b/tests/path.test.ts @@ -1,5 +1,6 @@ import { createPathTagFunction, encodeURIPath } from 'scan-documents/internal/utils/path'; import { inspect } from 'node:util'; +import { runInNewContext } from 'node:vm'; describe('path template tag function', () => { test('validates input', () => { @@ -32,9 +33,114 @@ describe('path template tag function', () => { 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 + // We need to test how %2E is handled, so we use a custom encoder that does no escaping. const rawPath = createPathTagFunction((s) => s); + const emptyObject = {}; + const mathObject = Math; + const numberObject = new Number(); + const stringObject = new String(); + const basicClass = new (class {})(); + const classWithToString = new (class { + toString() { + return 'ok'; + } + })(); + + // Invalid values + expect(() => rawPath`/a/${null}/b`).toThrow( + 'Path parameters result in path with invalid segments:\n' + + 'Value of type Null is not a valid path parameter\n' + + '/a/null/b\n' + + ' ^^^^', + ); + expect(() => rawPath`/a/${undefined}/b`).toThrow( + 'Path parameters result in path with invalid segments:\n' + + 'Value of type Undefined is not a valid path parameter\n' + + '/a/undefined/b\n' + + ' ^^^^^^^^^', + ); + expect(() => rawPath`/a/${emptyObject}/b`).toThrow( + 'Path parameters result in path with invalid segments:\n' + + 'Value of type Object is not a valid path parameter\n' + + '/a/[object Object]/b\n' + + ' ^^^^^^^^^^^^^^^', + ); + expect(() => rawPath`?${mathObject}`).toThrow( + 'Path parameters result in path with invalid segments:\n' + + 'Value of type Math is not a valid path parameter\n' + + '?[object Math]\n' + + ' ^^^^^^^^^^^^^', + ); + expect(() => rawPath`/${basicClass}`).toThrow( + 'Path parameters result in path with invalid segments:\n' + + 'Value of type Object is not a valid path parameter\n' + + '/[object Object]\n' + + ' ^^^^^^^^^^^^^^', + ); + expect(() => rawPath`/../${''}`).toThrow( + 'Path parameters result in path with invalid segments:\n' + + 'Value ".." can\'t be safely passed as a path parameter\n' + + '/../\n' + + ' ^^', + ); + expect(() => rawPath`/../${{}}`).toThrow( + 'Path parameters result in path with invalid segments:\n' + + 'Value ".." can\'t be safely passed as a path parameter\n' + + 'Value of type Object is not a valid path parameter\n' + + '/../[object Object]\n' + + ' ^^ ^^^^^^^^^^^^^^', + ); + + // Valid values + expect(rawPath`/${0}`).toBe('/0'); + expect(rawPath`/${''}`).toBe('/'); + expect(rawPath`/${numberObject}`).toBe('/0'); + expect(rawPath`${stringObject}/`).toBe('/'); + expect(rawPath`/${classWithToString}`).toBe('/ok'); + + // We need to check what happens with cross-realm values, which we might get from + // Jest or other frames in a browser. + + const newRealm = runInNewContext('globalThis'); + expect(newRealm.Object).not.toBe(Object); + + const crossRealmObject = newRealm.Object(); + const crossRealmMathObject = newRealm.Math; + const crossRealmNumber = new newRealm.Number(); + const crossRealmString = new newRealm.String(); + const crossRealmClass = new (class extends newRealm.Object {})(); + const crossRealmClassWithToString = new (class extends newRealm.Object { + toString() { + return 'ok'; + } + })(); + + // Invalid cross-realm values + expect(() => rawPath`/a/${crossRealmObject}/b`).toThrow( + 'Path parameters result in path with invalid segments:\n' + + 'Value of type Object is not a valid path parameter\n' + + '/a/[object Object]/b\n' + + ' ^^^^^^^^^^^^^^^', + ); + expect(() => rawPath`?${crossRealmMathObject}`).toThrow( + 'Path parameters result in path with invalid segments:\n' + + 'Value of type Math is not a valid path parameter\n' + + '?[object Math]\n' + + ' ^^^^^^^^^^^^^', + ); + expect(() => rawPath`/${crossRealmClass}`).toThrow( + 'Path parameters result in path with invalid segments:\n' + + 'Value of type Object is not a valid path parameter\n' + + '/[object Object]\n' + + ' ^^^^^^^^^^^^^^^', + ); + + // Valid cross-realm values + expect(rawPath`/${crossRealmNumber}`).toBe('/0'); + expect(rawPath`${crossRealmString}/`).toBe('/'); + expect(rawPath`/${crossRealmClassWithToString}`).toBe('/ok'); + const results: { [pathParts: string]: { [params: string]: { valid: boolean; result?: string; error?: string }; @@ -85,6 +191,7 @@ describe('path template tag function', () => { valid: false, error: 'Error: Path parameters result in path with invalid segments:\n' + + 'Value "%2E%2e" can\'t be safely passed as a path parameter\n' + '/path_params/%2E%2e/a\n' + ' ^^^^^^', }, @@ -92,6 +199,7 @@ describe('path template tag function', () => { valid: false, error: 'Error: Path parameters result in path with invalid segments:\n' + + 'Value "%2E" can\'t be safely passed as a path parameter\n' + '/path_params/%2E/a\n' + ' ^^^', }, @@ -103,6 +211,7 @@ describe('path template tag function', () => { valid: false, error: 'Error: Path parameters result in path with invalid segments:\n' + + 'Value "%2e%2E" can\'t be safely passed as a path parameter\n' + '/path_params/%2e%2E/\n' + ' ^^^^^^', }, @@ -110,6 +219,7 @@ describe('path template tag function', () => { valid: false, error: 'Error: Path parameters result in path with invalid segments:\n' + + 'Value "%2e" can\'t be safely passed as a path parameter\n' + '/path_params/%2e/\n' + ' ^^^', }, @@ -121,6 +231,7 @@ describe('path template tag function', () => { valid: false, error: 'Error: Path parameters result in path with invalid segments:\n' + + 'Value "%2E" can\'t be safely passed as a path parameter\n' + '/path_params/%2E\n' + ' ^^^', }, @@ -128,6 +239,7 @@ describe('path template tag function', () => { valid: false, error: 'Error: Path parameters result in path with invalid segments:\n' + + 'Value "%2E%2e" can\'t be safely passed as a path parameter\n' + '/path_params/%2E%2e\n' + ' ^^^^^^', }, @@ -137,11 +249,17 @@ describe('path template tag function', () => { '["x"]': { valid: true, result: 'x/a' }, '["%2E"]': { valid: false, - error: 'Error: Path parameters result in path with invalid segments:\n%2E/a\n^^^', + error: + 'Error: Path parameters result in path with invalid segments:\n' + + 'Value "%2E" can\'t be safely passed as a path parameter\n%2E/a\n^^^', }, '["%2e%2E"]': { valid: false, - error: 'Error: Path parameters result in path with invalid segments:\n' + '%2e%2E/a\n' + '^^^^^^', + error: + 'Error: Path parameters result in path with invalid segments:\n' + + 'Value "%2e%2E" can\'t be safely passed as a path parameter\n' + + '%2e%2E/a\n' + + '^^^^^^', }, }, '["","/"]': { @@ -149,11 +267,18 @@ describe('path template tag function', () => { '[""]': { valid: true, result: '/' }, '["%2E%2e"]': { valid: false, - error: 'Error: Path parameters result in path with invalid segments:\n' + '%2E%2e/\n' + '^^^^^^', + error: + 'Error: Path parameters result in path with invalid segments:\n' + + 'Value "%2E%2e" can\'t be safely passed as a path parameter\n' + + '%2E%2e/\n' + + '^^^^^^', }, '["."]': { valid: false, - error: 'Error: Path parameters result in path with invalid segments:\n./\n^', + error: + 'Error: Path parameters result in path with invalid segments:\n' + + 'Value "." can\'t be safely passed as a path parameter\n' + + './\n^', }, }, '["",""]': { @@ -161,11 +286,17 @@ describe('path template tag function', () => { '["x"]': { valid: true, result: 'x' }, '[".."]': { valid: false, - error: 'Error: Path parameters result in path with invalid segments:\n..\n^^', + error: + 'Error: Path parameters result in path with invalid segments:\n' + + 'Value ".." can\'t be safely passed as a path parameter\n' + + '..\n^^', }, '["."]': { valid: false, - error: 'Error: Path parameters result in path with invalid segments:\n.\n^', + error: + 'Error: Path parameters result in path with invalid segments:\n' + + 'Value "." can\'t be safely passed as a path parameter\n' + + '.\n^', }, }, '["a"]': {}, @@ -185,6 +316,7 @@ describe('path template tag function', () => { valid: false, error: 'Error: Path parameters result in path with invalid segments:\n' + + 'Value "%2E%2E" can\'t be safely passed as a path parameter\n' + '/path_params/%2E%2E?beta=true\n' + ' ^^^^^^', }, @@ -192,6 +324,7 @@ describe('path template tag function', () => { valid: false, error: 'Error: Path parameters result in path with invalid segments:\n' + + 'Value "%2e%2E" can\'t be safely passed as a path parameter\n' + '/path_params/%2e%2E?beta=true\n' + ' ^^^^^^', }, @@ -203,6 +336,7 @@ describe('path template tag function', () => { valid: false, error: 'Error: Path parameters result in path with invalid segments:\n' + + 'Value "." can\'t be safely passed as a path parameter\n' + '/path_params/.?beta=true\n' + ' ^', }, @@ -210,6 +344,7 @@ describe('path template tag function', () => { valid: false, error: 'Error: Path parameters result in path with invalid segments:\n' + + 'Value "%2e." can\'t be safely passed as a path parameter\n' + '/path_params/%2e.?beta=true\n' + ' ^^^^', }, @@ -221,6 +356,8 @@ describe('path template tag function', () => { valid: false, error: 'Error: Path parameters result in path with invalid segments:\n' + + 'Value "." can\'t be safely passed as a path parameter\n' + + 'Value "%2e" can\'t be safely passed as a path parameter\n' + '/path_params/./%2e/download\n' + ' ^ ^^^', }, @@ -228,6 +365,8 @@ describe('path template tag function', () => { valid: false, error: 'Error: Path parameters result in path with invalid segments:\n' + + 'Value "%2E%2e" can\'t be safely passed as a path parameter\n' + + 'Value "%2e" can\'t be safely passed as a path parameter\n' + '/path_params/%2E%2e/%2e/download\n' + ' ^^^^^^ ^^^', }, @@ -243,6 +382,7 @@ describe('path template tag function', () => { valid: false, error: 'Error: Path parameters result in path with invalid segments:\n' + + 'Value "%2E" can\'t be safely passed as a path parameter\n' + '/path_params/%2E/download\n' + ' ^^^', }, @@ -250,6 +390,7 @@ describe('path template tag function', () => { valid: false, error: 'Error: Path parameters result in path with invalid segments:\n' + + 'Value "%2E." can\'t be safely passed as a path parameter\n' + '/path_params/%2E./download\n' + ' ^^^^', }, @@ -261,6 +402,7 @@ describe('path template tag function', () => { valid: false, error: 'Error: Path parameters result in path with invalid segments:\n' + + 'Value "." can\'t be safely passed as a path parameter\n' + '/path_params/./download\n' + ' ^', }, @@ -268,6 +410,7 @@ describe('path template tag function', () => { valid: false, error: 'Error: Path parameters result in path with invalid segments:\n' + + 'Value ".." can\'t be safely passed as a path parameter\n' + '/path_params/../download\n' + ' ^^', }, @@ -279,6 +422,7 @@ describe('path template tag function', () => { valid: false, error: 'Error: Path parameters result in path with invalid segments:\n' + + 'Value ".." can\'t be safely passed as a path parameter\n' + '/path_params/../download\n' + ' ^^', }, From 26a2df16f3133c6f3ebfa06a906ccbdb667b763c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 3 Jul 2025 04:10:00 +0000 Subject: [PATCH 50/91] chore: add docs to RequestOptions type --- src/client.ts | 2 ++ src/internal/request-options.ts | 53 +++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/src/client.ts b/src/client.ts index 7370a77..a547b7b 100644 --- a/src/client.ts +++ b/src/client.ts @@ -84,6 +84,8 @@ export interface ClientOptions { * * 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. + * + * @unit milliseconds */ timeout?: number | undefined; /** diff --git a/src/internal/request-options.ts b/src/internal/request-options.ts index 7de032f..2aabf9a 100644 --- a/src/internal/request-options.ts +++ b/src/internal/request-options.ts @@ -9,17 +9,70 @@ import { type HeadersLike } from './headers'; export type FinalRequestOptions = RequestOptions & { method: HTTPMethod; path: string }; export type RequestOptions = { + /** + * The HTTP method for the request (e.g., 'get', 'post', 'put', 'delete'). + */ method?: HTTPMethod; + + /** + * The URL path for the request. + * + * @example "/v1/foo" + */ path?: string; + + /** + * Query parameters to include in the request URL. + */ query?: object | undefined | null; + + /** + * The request body. Can be a string, JSON object, FormData, or other supported types. + */ body?: unknown; + + /** + * HTTP headers to include with the request. Can be a Headers object, plain object, or array of tuples. + */ headers?: HeadersLike; + + /** + * 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; + stream?: boolean | 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. + * + * @unit milliseconds + */ timeout?: number; + + /** + * Additional `RequestInit` options to be passed to the underlying `fetch` call. + * These options will be merged with the client's default fetch options. + */ fetchOptions?: MergedRequestInit; + + /** + * An AbortSignal that can be used to cancel the request. + */ signal?: AbortSignal | undefined | null; + + /** + * A unique key for this request to enable idempotency. + */ idempotencyKey?: string; + + /** + * Override the default base URL for this specific request. + */ defaultBaseURL?: string | undefined; __binaryResponse?: boolean | undefined; From 064caed6799b56c06d441e02319f31ca79f0549f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 10 Jul 2025 04:54:59 +0000 Subject: [PATCH 51/91] chore: make some internal functions async --- src/client.ts | 25 ++++++++++++++----------- tests/index.test.ts | 30 +++++++++++++++--------------- 2 files changed, 29 insertions(+), 26 deletions(-) diff --git a/src/client.ts b/src/client.ts index a547b7b..eba1ad8 100644 --- a/src/client.ts +++ b/src/client.ts @@ -211,7 +211,7 @@ export class ScanDocuments { * 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)({ + const client = new (this.constructor as any as new (props: ClientOptions) => typeof this)({ ...this._options, baseURL: this.baseURL, maxRetries: this.maxRetries, @@ -223,6 +223,7 @@ export class ScanDocuments { apiKey: this.apiKey, ...options, }); + return client; } /** @@ -240,7 +241,7 @@ export class ScanDocuments { return; } - protected authHeaders(opts: FinalRequestOptions): NullableHeaders | undefined { + protected async authHeaders(opts: FinalRequestOptions): Promise { return buildHeaders([{ 'x-api-key': this.apiKey }]); } @@ -372,7 +373,9 @@ export class ScanDocuments { await this.prepareOptions(options); - const { req, url, timeout } = this.buildRequest(options, { retryCount: maxRetries - retriesRemaining }); + const { req, url, timeout } = await this.buildRequest(options, { + retryCount: maxRetries - retriesRemaining, + }); await this.prepareRequest(req, { url, options }); @@ -450,7 +453,7 @@ export class ScanDocuments { } with status ${response.status} in ${headersTime - startTime}ms`; if (!response.ok) { - const shouldRetry = this.shouldRetry(response); + const shouldRetry = await this.shouldRetry(response); if (retriesRemaining && shouldRetry) { const retryMessage = `retrying, ${retriesRemaining} attempts remaining`; @@ -549,7 +552,7 @@ export class ScanDocuments { } } - private shouldRetry(response: Response): boolean { + private async shouldRetry(response: Response): Promise { // Note this is not a standard header. const shouldRetryHeader = response.headers.get('x-should-retry'); @@ -626,10 +629,10 @@ export class ScanDocuments { return sleepSeconds * jitter * 1000; } - buildRequest( + async buildRequest( inputOptions: FinalRequestOptions, { retryCount = 0 }: { retryCount?: number } = {}, - ): { req: FinalizedRequestInit; url: string; timeout: number } { + ): Promise<{ req: FinalizedRequestInit; url: string; timeout: number }> { const options = { ...inputOptions }; const { method, path, query, defaultBaseURL } = options; @@ -637,7 +640,7 @@ export class ScanDocuments { 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 reqHeaders = await this.buildHeaders({ options: inputOptions, method, bodyHeaders, retryCount }); const req: FinalizedRequestInit = { method, @@ -653,7 +656,7 @@ export class ScanDocuments { return { req, url, timeout: options.timeout }; } - private buildHeaders({ + private async buildHeaders({ options, method, bodyHeaders, @@ -663,7 +666,7 @@ export class ScanDocuments { method: HTTPMethod; bodyHeaders: HeadersLike; retryCount: number; - }): Headers { + }): Promise { let idempotencyHeaders: HeadersLike = {}; if (this.idempotencyHeader && method !== 'get') { if (!options.idempotencyKey) options.idempotencyKey = this.defaultIdempotencyKey(); @@ -679,7 +682,7 @@ export class ScanDocuments { ...(options.timeout ? { 'X-Stainless-Timeout': String(Math.trunc(options.timeout / 1000)) } : {}), ...getPlatformHeaders(), }, - this.authHeaders(options), + await this.authHeaders(options), this._options.defaultHeaders, bodyHeaders, options.headers, diff --git a/tests/index.test.ts b/tests/index.test.ts index 92a38ff..a75ea2b 100644 --- a/tests/index.test.ts +++ b/tests/index.test.ts @@ -26,13 +26,13 @@ describe('instantiate client', () => { apiKey: 'My API Key', }); - test('they are used in the request', () => { - const { req } = client.buildRequest({ path: '/foo', method: 'post' }); + test('they are used in the request', async () => { + const { req } = await client.buildRequest({ path: '/foo', method: 'post' }); expect(req.headers.get('x-my-default-header')).toEqual('2'); }); - test('can ignore `undefined` and leave the default', () => { - const { req } = client.buildRequest({ + test('can ignore `undefined` and leave the default', async () => { + const { req } = await client.buildRequest({ path: '/foo', method: 'post', headers: { 'X-My-Default-Header': undefined }, @@ -40,8 +40,8 @@ describe('instantiate client', () => { expect(req.headers.get('x-my-default-header')).toEqual('2'); }); - test('can be removed with `null`', () => { - const { req } = client.buildRequest({ + test('can be removed with `null`', async () => { + const { req } = await client.buildRequest({ path: '/foo', method: 'post', headers: { 'X-My-Default-Header': null }, @@ -354,7 +354,7 @@ describe('instantiate client', () => { }); describe('withOptions', () => { - test('creates a new client with overridden options', () => { + test('creates a new client with overridden options', async () => { const client = new ScanDocuments({ baseURL: 'http://localhost:5000/', maxRetries: 3, @@ -379,7 +379,7 @@ describe('instantiate client', () => { expect(newClient.constructor).toBe(client.constructor); }); - test('inherits options from the parent client', () => { + test('inherits options from the parent client', async () => { const client = new ScanDocuments({ baseURL: 'http://localhost:5000/', defaultHeaders: { 'X-Test-Header': 'test-value' }, @@ -394,7 +394,7 @@ describe('instantiate client', () => { // 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' }); + const { req } = await newClient.buildRequest({ path: '/foo', method: 'get' }); expect(req.headers.get('x-test-header')).toEqual('test-value'); }); @@ -448,8 +448,8 @@ describe('request building', () => { const client = new ScanDocuments({ apiKey: 'My API Key' }); describe('custom headers', () => { - test('handles undefined', () => { - const { req } = client.buildRequest({ + test('handles undefined', async () => { + const { req } = await client.buildRequest({ path: '/foo', method: 'post', body: { value: 'hello' }, @@ -484,8 +484,8 @@ describe('default encoder', () => { } } for (const jsonValue of [{}, [], { __proto__: null }, new Serializable(), new Collection(['item'])]) { - test(`serializes ${util.inspect(jsonValue)} as json`, () => { - const { req } = client.buildRequest({ + test(`serializes ${util.inspect(jsonValue)} as json`, async () => { + const { req } = await client.buildRequest({ path: '/foo', method: 'post', body: jsonValue, @@ -508,7 +508,7 @@ describe('default encoder', () => { asyncIterable, ]) { test(`converts ${util.inspect(streamValue)} to ReadableStream`, async () => { - const { req } = client.buildRequest({ + const { req } = await client.buildRequest({ path: '/foo', method: 'post', body: streamValue, @@ -521,7 +521,7 @@ describe('default encoder', () => { } test(`can set content-type for ReadableStream`, async () => { - const { req } = client.buildRequest({ + const { req } = await client.buildRequest({ path: '/foo', method: 'post', body: new Response('a\nb\nc\n').body, From 436421e66b382295d19149478a5cabb21bce12a6 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 11 Jul 2025 02:13:12 +0000 Subject: [PATCH 52/91] feat(mcp): support filtering tool results by a jq expression --- packages/mcp-server/package.json | 1 + packages/mcp-server/src/filtering.ts | 13 +++++++++++++ packages/mcp-server/src/tools/events/list-events.ts | 3 ++- packages/mcp-server/src/tools/files/delete-files.ts | 9 ++++++++- .../mcp-server/src/tools/files/download-files.ts | 9 ++++++++- packages/mcp-server/src/tools/files/list-files.ts | 12 ++++++++++-- .../mcp-server/src/tools/files/retrieve-files.ts | 12 ++++++++++-- packages/mcp-server/src/tools/files/upload-files.ts | 12 ++++++++++-- .../apply-effect-image-operations.ts | 3 ++- .../image-operations/convert-image-operations.ts | 3 ++- .../detect-documents-image-operations.ts | 3 ++- .../extract-text-image-operations.ts | 3 ++- .../tools/image-operations/scan-image-operations.ts | 2 +- .../tools/image-operations/warp-image-operations.ts | 2 +- .../pdf-operations/extract-pages-pdf-operations.ts | 3 ++- .../tools/pdf-operations/merge-pdf-operations.ts | 3 ++- .../tools/pdf-operations/render-pdf-operations.ts | 3 ++- .../tools/pdf-operations/split-pdf-operations.ts | 3 ++- packages/mcp-server/src/tools/tasks/list-tasks.ts | 3 ++- .../mcp-server/src/tools/tasks/retrieve-tasks.ts | 3 ++- 20 files changed, 84 insertions(+), 21 deletions(-) create mode 100644 packages/mcp-server/src/filtering.ts diff --git a/packages/mcp-server/package.json b/packages/mcp-server/package.json index 4939d5b..53dba89 100644 --- a/packages/mcp-server/package.json +++ b/packages/mcp-server/package.json @@ -29,6 +29,7 @@ "dependencies": { "scan-documents": "file:../../dist/", "@modelcontextprotocol/sdk": "^1.11.5", + "jq-web": "^0.6.2", "yargs": "^17.7.2", "@cloudflare/cabidela": "^0.2.4", "zod": "^3.25.20", diff --git a/packages/mcp-server/src/filtering.ts b/packages/mcp-server/src/filtering.ts new file mode 100644 index 0000000..e560736 --- /dev/null +++ b/packages/mcp-server/src/filtering.ts @@ -0,0 +1,13 @@ +export async function maybeFilter(args: Record | undefined, response: any): Promise { + const jqFilter = args?.['jq_filter']; + if (jqFilter && typeof jqFilter === 'string') { + return await jq(response, jqFilter); + } else { + return response; + } +} + +var jqWeb = require('jq-web'); +async function jq(json: any, jqFilter: string) { + return (await jqWeb).json(json, jqFilter); +} diff --git a/packages/mcp-server/src/tools/events/list-events.ts b/packages/mcp-server/src/tools/events/list-events.ts index 6dc693f..41dc193 100644 --- a/packages/mcp-server/src/tools/events/list-events.ts +++ b/packages/mcp-server/src/tools/events/list-events.ts @@ -17,7 +17,8 @@ export const metadata: Metadata = { export const tool: Tool = { name: 'list_events', - description: 'Retrieves a paginated list of events belonging to the authenticated user.', + description: + "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nRetrieves a paginated list of events belonging to the authenticated user.", inputSchema: { type: 'object', properties: { diff --git a/packages/mcp-server/src/tools/files/delete-files.ts b/packages/mcp-server/src/tools/files/delete-files.ts index 744d26d..ba194a2 100644 --- a/packages/mcp-server/src/tools/files/delete-files.ts +++ b/packages/mcp-server/src/tools/files/delete-files.ts @@ -17,13 +17,20 @@ export const metadata: Metadata = { export const tool: Tool = { name: 'delete_files', - description: 'Deletes a specific file by its ID.', + description: + "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nDeletes a specific file by its ID.\n\n# Response Schema\n```json\n{\n type: 'object',\n properties: {}\n}\n```", inputSchema: { type: 'object', properties: { id: { type: 'string', }, + jq_filter: { + type: 'string', + title: 'jq Filter', + description: + 'A jq filter to apply to the response to include certain fields. Consult the output schema in the tool description to see the fields that are available.\n\nFor example: to include only the `name` field in every object of a results array, you can provide ".results[].name".\n\nFor more information, see the [jq documentation](https://jqlang.org/manual/).', + }, }, }, }; diff --git a/packages/mcp-server/src/tools/files/download-files.ts b/packages/mcp-server/src/tools/files/download-files.ts index 564189c..56c785e 100644 --- a/packages/mcp-server/src/tools/files/download-files.ts +++ b/packages/mcp-server/src/tools/files/download-files.ts @@ -17,13 +17,20 @@ export const metadata: Metadata = { export const tool: Tool = { name: 'download_files', - description: 'Downloads the content of a specific file by its ID.', + description: + "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nDownloads the content of a specific file by its ID.\n\n# Response Schema\n```json\n{\n type: 'string'\n}\n```", inputSchema: { type: 'object', properties: { id: { type: 'string', }, + jq_filter: { + type: 'string', + title: 'jq Filter', + description: + 'A jq filter to apply to the response to include certain fields. Consult the output schema in the tool description to see the fields that are available.\n\nFor example: to include only the `name` field in every object of a results array, you can provide ".results[].name".\n\nFor more information, see the [jq documentation](https://jqlang.org/manual/).', + }, }, }, }; diff --git a/packages/mcp-server/src/tools/files/list-files.ts b/packages/mcp-server/src/tools/files/list-files.ts index 4419839..e9639fd 100644 --- a/packages/mcp-server/src/tools/files/list-files.ts +++ b/packages/mcp-server/src/tools/files/list-files.ts @@ -1,5 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +import { maybeFilter } from 'scan-documents-mcp/filtering'; import { asTextContentResult } from 'scan-documents-mcp/tools/types'; import { Tool } from '@modelcontextprotocol/sdk/types.js'; @@ -17,7 +18,8 @@ export const metadata: Metadata = { export const tool: Tool = { name: 'list_files', - description: 'Retrieves a paginated list of files belonging to the authenticated user.', + description: + "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nRetrieves a paginated list of files belonging to the authenticated user.\n\n# Response Schema\n```json\n{\n type: 'object',\n properties: {\n data: {\n type: 'array',\n description: 'The list of files',\n items: {\n $ref: '#/$defs/file'\n }\n },\n links: {\n type: 'object',\n properties: {\n next: {\n type: 'string',\n description: 'The URL to the next page of results'\n },\n previous: {\n type: 'string',\n description: 'The URL to the previous page of results'\n }\n },\n required: [ 'next',\n 'previous'\n ]\n }\n },\n required: [ 'data',\n 'links'\n ],\n $defs: {\n file: {\n anyOf: [ {\n type: 'object',\n title: 'Image Response',\n description: 'The response for an image file',\n properties: {\n id: {\n type: 'string',\n description: 'The id of the file'\n },\n created_at: {\n type: 'string',\n description: 'The creation date of the file in ISO format'\n },\n name: {\n type: 'string',\n description: 'The name of the file'\n },\n properties: {\n type: 'object',\n properties: {\n height: {\n type: 'number',\n description: 'The height of the image in pixels'\n },\n size: {\n type: 'number',\n description: 'The size of the image in bytes'\n },\n width: {\n type: 'number',\n description: 'The width of the image in pixels'\n }\n },\n required: [ 'height',\n 'size',\n 'width'\n ]\n },\n task_id: {\n type: 'string',\n description: 'The id of the task that generated this file, if any'\n },\n type: {\n type: 'string',\n description: 'The MIME type of the file',\n enum: [ 'image/png',\n 'image/jpeg',\n 'image/webp'\n ]\n }\n },\n required: [ 'id',\n 'created_at',\n 'name',\n 'properties',\n 'task_id',\n 'type'\n ]\n },\n {\n type: 'object',\n title: 'Document Response',\n description: 'The response for a document file',\n properties: {\n id: {\n type: 'string',\n description: 'The id of the file'\n },\n created_at: {\n type: 'string',\n description: 'The creation date of the file in ISO format'\n },\n name: {\n type: 'string',\n description: 'The name of the file'\n },\n properties: {\n type: 'object',\n properties: {\n page_count: {\n type: 'number',\n description: 'The number of pages in the document'\n },\n size: {\n type: 'number',\n description: 'The size of the document in bytes'\n }\n },\n required: [ 'page_count',\n 'size'\n ]\n },\n task_id: {\n type: 'string',\n description: 'The id of the task that generated this file, if any'\n },\n type: {\n type: 'string',\n description: 'The MIME type of the file',\n enum: [ 'application/pdf'\n ]\n }\n },\n required: [ 'id',\n 'created_at',\n 'name',\n 'properties',\n 'task_id',\n 'type'\n ]\n }\n ],\n title: 'File Response',\n description: 'The response for a file. Properties depend on the file type.'\n }\n }\n}\n```", inputSchema: { type: 'object', properties: { @@ -29,13 +31,19 @@ export const tool: Tool = { type: 'number', description: 'The number of elements to retrieve', }, + jq_filter: { + type: 'string', + title: 'jq Filter', + description: + 'A jq filter to apply to the response to include certain fields. Consult the output schema in the tool description to see the fields that are available.\n\nFor example: to include only the `name` field in every object of a results array, you can provide ".results[].name".\n\nFor more information, see the [jq documentation](https://jqlang.org/manual/).', + }, }, }, }; export const handler = async (client: ScanDocuments, args: Record | undefined) => { const body = args as any; - return asTextContentResult(await client.files.list(body)); + return asTextContentResult(await maybeFilter(args, await client.files.list(body))); }; export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/files/retrieve-files.ts b/packages/mcp-server/src/tools/files/retrieve-files.ts index 9b35a64..be49d1d 100644 --- a/packages/mcp-server/src/tools/files/retrieve-files.ts +++ b/packages/mcp-server/src/tools/files/retrieve-files.ts @@ -1,5 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +import { maybeFilter } from 'scan-documents-mcp/filtering'; import { asTextContentResult } from 'scan-documents-mcp/tools/types'; import { Tool } from '@modelcontextprotocol/sdk/types.js'; @@ -17,20 +18,27 @@ export const metadata: Metadata = { export const tool: Tool = { name: 'retrieve_files', - description: 'Retrieves the data for a specific file by its ID.', + description: + "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nRetrieves the data for a specific file by its ID.\n\n# Response Schema\n```json\n{\n $ref: '#/$defs/file',\n $defs: {\n file: {\n anyOf: [ {\n type: 'object',\n title: 'Image Response',\n description: 'The response for an image file',\n properties: {\n id: {\n type: 'string',\n description: 'The id of the file'\n },\n created_at: {\n type: 'string',\n description: 'The creation date of the file in ISO format'\n },\n name: {\n type: 'string',\n description: 'The name of the file'\n },\n properties: {\n type: 'object',\n properties: {\n height: {\n type: 'number',\n description: 'The height of the image in pixels'\n },\n size: {\n type: 'number',\n description: 'The size of the image in bytes'\n },\n width: {\n type: 'number',\n description: 'The width of the image in pixels'\n }\n },\n required: [ 'height',\n 'size',\n 'width'\n ]\n },\n task_id: {\n type: 'string',\n description: 'The id of the task that generated this file, if any'\n },\n type: {\n type: 'string',\n description: 'The MIME type of the file',\n enum: [ 'image/png',\n 'image/jpeg',\n 'image/webp'\n ]\n }\n },\n required: [ 'id',\n 'created_at',\n 'name',\n 'properties',\n 'task_id',\n 'type'\n ]\n },\n {\n type: 'object',\n title: 'Document Response',\n description: 'The response for a document file',\n properties: {\n id: {\n type: 'string',\n description: 'The id of the file'\n },\n created_at: {\n type: 'string',\n description: 'The creation date of the file in ISO format'\n },\n name: {\n type: 'string',\n description: 'The name of the file'\n },\n properties: {\n type: 'object',\n properties: {\n page_count: {\n type: 'number',\n description: 'The number of pages in the document'\n },\n size: {\n type: 'number',\n description: 'The size of the document in bytes'\n }\n },\n required: [ 'page_count',\n 'size'\n ]\n },\n task_id: {\n type: 'string',\n description: 'The id of the task that generated this file, if any'\n },\n type: {\n type: 'string',\n description: 'The MIME type of the file',\n enum: [ 'application/pdf'\n ]\n }\n },\n required: [ 'id',\n 'created_at',\n 'name',\n 'properties',\n 'task_id',\n 'type'\n ]\n }\n ],\n title: 'File Response',\n description: 'The response for a file. Properties depend on the file type.'\n }\n }\n}\n```", inputSchema: { type: 'object', properties: { id: { type: 'string', }, + jq_filter: { + type: 'string', + title: 'jq Filter', + description: + 'A jq filter to apply to the response to include certain fields. Consult the output schema in the tool description to see the fields that are available.\n\nFor example: to include only the `name` field in every object of a results array, you can provide ".results[].name".\n\nFor more information, see the [jq documentation](https://jqlang.org/manual/).', + }, }, }, }; export const handler = async (client: ScanDocuments, args: Record | undefined) => { const { id, ...body } = args as any; - return asTextContentResult(await client.files.retrieve(id)); + return asTextContentResult(await maybeFilter(args, await client.files.retrieve(id))); }; export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/files/upload-files.ts b/packages/mcp-server/src/tools/files/upload-files.ts index af089e9..87635a9 100644 --- a/packages/mcp-server/src/tools/files/upload-files.ts +++ b/packages/mcp-server/src/tools/files/upload-files.ts @@ -1,5 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. +import { maybeFilter } from 'scan-documents-mcp/filtering'; import { asTextContentResult } from 'scan-documents-mcp/tools/types'; import { Tool } from '@modelcontextprotocol/sdk/types.js'; @@ -17,7 +18,8 @@ export const metadata: Metadata = { export const tool: Tool = { name: 'upload_files', - description: "Uploads a file to the user's storage. The file size is limited to 10MB.", + description: + "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nUploads a file to the user's storage. The file size is limited to 10MB.\n\n# Response Schema\n```json\n{\n $ref: '#/$defs/file',\n $defs: {\n file: {\n anyOf: [ {\n type: 'object',\n title: 'Image Response',\n description: 'The response for an image file',\n properties: {\n id: {\n type: 'string',\n description: 'The id of the file'\n },\n created_at: {\n type: 'string',\n description: 'The creation date of the file in ISO format'\n },\n name: {\n type: 'string',\n description: 'The name of the file'\n },\n properties: {\n type: 'object',\n properties: {\n height: {\n type: 'number',\n description: 'The height of the image in pixels'\n },\n size: {\n type: 'number',\n description: 'The size of the image in bytes'\n },\n width: {\n type: 'number',\n description: 'The width of the image in pixels'\n }\n },\n required: [ 'height',\n 'size',\n 'width'\n ]\n },\n task_id: {\n type: 'string',\n description: 'The id of the task that generated this file, if any'\n },\n type: {\n type: 'string',\n description: 'The MIME type of the file',\n enum: [ 'image/png',\n 'image/jpeg',\n 'image/webp'\n ]\n }\n },\n required: [ 'id',\n 'created_at',\n 'name',\n 'properties',\n 'task_id',\n 'type'\n ]\n },\n {\n type: 'object',\n title: 'Document Response',\n description: 'The response for a document file',\n properties: {\n id: {\n type: 'string',\n description: 'The id of the file'\n },\n created_at: {\n type: 'string',\n description: 'The creation date of the file in ISO format'\n },\n name: {\n type: 'string',\n description: 'The name of the file'\n },\n properties: {\n type: 'object',\n properties: {\n page_count: {\n type: 'number',\n description: 'The number of pages in the document'\n },\n size: {\n type: 'number',\n description: 'The size of the document in bytes'\n }\n },\n required: [ 'page_count',\n 'size'\n ]\n },\n task_id: {\n type: 'string',\n description: 'The id of the task that generated this file, if any'\n },\n type: {\n type: 'string',\n description: 'The MIME type of the file',\n enum: [ 'application/pdf'\n ]\n }\n },\n required: [ 'id',\n 'created_at',\n 'name',\n 'properties',\n 'task_id',\n 'type'\n ]\n }\n ],\n title: 'File Response',\n description: 'The response for a file. Properties depend on the file type.'\n }\n }\n}\n```", inputSchema: { type: 'object', properties: { @@ -29,13 +31,19 @@ export const tool: Tool = { type: 'string', description: 'The name of the file', }, + jq_filter: { + type: 'string', + title: 'jq Filter', + description: + 'A jq filter to apply to the response to include certain fields. Consult the output schema in the tool description to see the fields that are available.\n\nFor example: to include only the `name` field in every object of a results array, you can provide ".results[].name".\n\nFor more information, see the [jq documentation](https://jqlang.org/manual/).', + }, }, }, }; export const handler = async (client: ScanDocuments, args: Record | undefined) => { const body = args as any; - return asTextContentResult(await client.files.upload(body)); + return asTextContentResult(await maybeFilter(args, await client.files.upload(body))); }; export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/image-operations/apply-effect-image-operations.ts b/packages/mcp-server/src/tools/image-operations/apply-effect-image-operations.ts index 02c917c..c8f14b4 100644 --- a/packages/mcp-server/src/tools/image-operations/apply-effect-image-operations.ts +++ b/packages/mcp-server/src/tools/image-operations/apply-effect-image-operations.ts @@ -17,7 +17,8 @@ export const metadata: Metadata = { export const tool: Tool = { name: 'apply_effect_image_operations', - description: 'Creates a task to apply a specified visual effect to an image.', + description: + "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nCreates a task to apply a specified visual effect to an image.", inputSchema: { type: 'object', properties: { diff --git a/packages/mcp-server/src/tools/image-operations/convert-image-operations.ts b/packages/mcp-server/src/tools/image-operations/convert-image-operations.ts index f642b09..28ed554 100644 --- a/packages/mcp-server/src/tools/image-operations/convert-image-operations.ts +++ b/packages/mcp-server/src/tools/image-operations/convert-image-operations.ts @@ -17,7 +17,8 @@ export const metadata: Metadata = { export const tool: Tool = { name: 'convert_image_operations', - description: 'Creates a task to convert an image file to a different format.', + description: + "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nCreates a task to convert an image file to a different format.", inputSchema: { type: 'object', anyOf: [ diff --git a/packages/mcp-server/src/tools/image-operations/detect-documents-image-operations.ts b/packages/mcp-server/src/tools/image-operations/detect-documents-image-operations.ts index 905f20f..4716107 100644 --- a/packages/mcp-server/src/tools/image-operations/detect-documents-image-operations.ts +++ b/packages/mcp-server/src/tools/image-operations/detect-documents-image-operations.ts @@ -17,7 +17,8 @@ export const metadata: Metadata = { export const tool: Tool = { name: 'detect_documents_image_operations', - description: 'Creates a task to detect document boundaries within an image.', + description: + "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nCreates a task to detect document boundaries within an image.", inputSchema: { type: 'object', properties: { diff --git a/packages/mcp-server/src/tools/image-operations/extract-text-image-operations.ts b/packages/mcp-server/src/tools/image-operations/extract-text-image-operations.ts index 2755a04..7577f29 100644 --- a/packages/mcp-server/src/tools/image-operations/extract-text-image-operations.ts +++ b/packages/mcp-server/src/tools/image-operations/extract-text-image-operations.ts @@ -17,7 +17,8 @@ export const metadata: Metadata = { export const tool: Tool = { name: 'extract_text_image_operations', - description: 'Creates a task to extract text from a specified image file.', + description: + "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nCreates a task to extract text from a specified image file.", inputSchema: { type: 'object', anyOf: [ diff --git a/packages/mcp-server/src/tools/image-operations/scan-image-operations.ts b/packages/mcp-server/src/tools/image-operations/scan-image-operations.ts index 108d4fb..ef68b47 100644 --- a/packages/mcp-server/src/tools/image-operations/scan-image-operations.ts +++ b/packages/mcp-server/src/tools/image-operations/scan-image-operations.ts @@ -18,7 +18,7 @@ export const metadata: Metadata = { export const tool: Tool = { name: 'scan_image_operations', description: - 'Creates a task to scan an image file. \nThis is an equivalent operation for `detect-documents` and `warp` combined, additionally it can apply effects to the scanned image.', + "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nCreates a task to scan an image file. \nThis is an equivalent operation for `detect-documents` and `warp` combined, additionally it can apply effects to the scanned image.", inputSchema: { type: 'object', properties: { diff --git a/packages/mcp-server/src/tools/image-operations/warp-image-operations.ts b/packages/mcp-server/src/tools/image-operations/warp-image-operations.ts index 90d6c92..f3f5143 100644 --- a/packages/mcp-server/src/tools/image-operations/warp-image-operations.ts +++ b/packages/mcp-server/src/tools/image-operations/warp-image-operations.ts @@ -18,7 +18,7 @@ export const metadata: Metadata = { export const tool: Tool = { name: 'warp_image_operations', description: - 'Creates a task to apply perspective correction (warp) to an image based on detected document boundaries.', + "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nCreates a task to apply perspective correction (warp) to an image based on detected document boundaries.", inputSchema: { type: 'object', properties: { diff --git a/packages/mcp-server/src/tools/pdf-operations/extract-pages-pdf-operations.ts b/packages/mcp-server/src/tools/pdf-operations/extract-pages-pdf-operations.ts index bee5b28..36c41f6 100644 --- a/packages/mcp-server/src/tools/pdf-operations/extract-pages-pdf-operations.ts +++ b/packages/mcp-server/src/tools/pdf-operations/extract-pages-pdf-operations.ts @@ -17,7 +17,8 @@ export const metadata: Metadata = { export const tool: Tool = { name: 'extract_pages_pdf_operations', - description: 'Creates a task to extract specific pages from a PDF file into a new PDF file.', + description: + "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nCreates a task to extract specific pages from a PDF file into a new PDF file.", inputSchema: { type: 'object', properties: { diff --git a/packages/mcp-server/src/tools/pdf-operations/merge-pdf-operations.ts b/packages/mcp-server/src/tools/pdf-operations/merge-pdf-operations.ts index 2aeeab2..d75296d 100644 --- a/packages/mcp-server/src/tools/pdf-operations/merge-pdf-operations.ts +++ b/packages/mcp-server/src/tools/pdf-operations/merge-pdf-operations.ts @@ -17,7 +17,8 @@ export const metadata: Metadata = { export const tool: Tool = { name: 'merge_pdf_operations', - description: 'Creates a task to merge multiple PDF and/or image files into a single PDF file.', + description: + "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nCreates a task to merge multiple PDF and/or image files into a single PDF file.", inputSchema: { type: 'object', properties: { diff --git a/packages/mcp-server/src/tools/pdf-operations/render-pdf-operations.ts b/packages/mcp-server/src/tools/pdf-operations/render-pdf-operations.ts index 6629703..73ec49e 100644 --- a/packages/mcp-server/src/tools/pdf-operations/render-pdf-operations.ts +++ b/packages/mcp-server/src/tools/pdf-operations/render-pdf-operations.ts @@ -17,7 +17,8 @@ export const metadata: Metadata = { export const tool: Tool = { name: 'render_pdf_operations', - description: 'Creates a task to render specified pages of a PDF file as images.', + description: + "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nCreates a task to render specified pages of a PDF file as images.", inputSchema: { type: 'object', properties: { diff --git a/packages/mcp-server/src/tools/pdf-operations/split-pdf-operations.ts b/packages/mcp-server/src/tools/pdf-operations/split-pdf-operations.ts index 89956cd..cc305d8 100644 --- a/packages/mcp-server/src/tools/pdf-operations/split-pdf-operations.ts +++ b/packages/mcp-server/src/tools/pdf-operations/split-pdf-operations.ts @@ -17,7 +17,8 @@ export const metadata: Metadata = { export const tool: Tool = { name: 'split_pdf_operations', - description: 'Creates a task to split a PDF file into multiple single-page PDF files.', + description: + "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nCreates a task to split a PDF file into multiple single-page PDF files.", inputSchema: { type: 'object', properties: { diff --git a/packages/mcp-server/src/tools/tasks/list-tasks.ts b/packages/mcp-server/src/tools/tasks/list-tasks.ts index d57788e..619abcd 100644 --- a/packages/mcp-server/src/tools/tasks/list-tasks.ts +++ b/packages/mcp-server/src/tools/tasks/list-tasks.ts @@ -17,7 +17,8 @@ export const metadata: Metadata = { export const tool: Tool = { name: 'list_tasks', - description: 'Retrieves a paginated list of tasks belonging to the authenticated user.', + description: + "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nRetrieves a paginated list of tasks belonging to the authenticated user.", inputSchema: { type: 'object', properties: { diff --git a/packages/mcp-server/src/tools/tasks/retrieve-tasks.ts b/packages/mcp-server/src/tools/tasks/retrieve-tasks.ts index 071d89f..2b559b3 100644 --- a/packages/mcp-server/src/tools/tasks/retrieve-tasks.ts +++ b/packages/mcp-server/src/tools/tasks/retrieve-tasks.ts @@ -17,7 +17,8 @@ export const metadata: Metadata = { export const tool: Tool = { name: 'retrieve_tasks', - description: 'Retrieves the data for a specific task by its ID.', + description: + "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nRetrieves the data for a specific task by its ID.", inputSchema: { type: 'object', properties: { From 7f50ae35b174c4e7863bfc71c71ce70f71893ef7 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 11 Jul 2025 03:59:20 +0000 Subject: [PATCH 53/91] fix(mcp): relax input type for asTextContextResult --- packages/mcp-server/src/tools/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/mcp-server/src/tools/types.ts b/packages/mcp-server/src/tools/types.ts index d3d1169..ddff304 100644 --- a/packages/mcp-server/src/tools/types.ts +++ b/packages/mcp-server/src/tools/types.ts @@ -47,7 +47,7 @@ export type HandlerFunction = ( args: Record | undefined, ) => Promise; -export function asTextContentResult(result: Object): ToolCallResult { +export function asTextContentResult(result: unknown): ToolCallResult { return { content: [ { From d2bee126b3794e12e7a66fd1df7600a89c7adf7a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 16 Jul 2025 03:48:09 +0000 Subject: [PATCH 54/91] fix(mcp): support jq filtering on cloudflare workers --- packages/mcp-server/package.json | 2 +- packages/mcp-server/src/filtering.ts | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/mcp-server/package.json b/packages/mcp-server/package.json index 53dba89..7a96a7b 100644 --- a/packages/mcp-server/package.json +++ b/packages/mcp-server/package.json @@ -29,7 +29,7 @@ "dependencies": { "scan-documents": "file:../../dist/", "@modelcontextprotocol/sdk": "^1.11.5", - "jq-web": "^0.6.2", + "jq-web": "https://github.com/stainless-api/jq-web/releases/download/v0.8.2/jq-web.tar.gz", "yargs": "^17.7.2", "@cloudflare/cabidela": "^0.2.4", "zod": "^3.25.20", diff --git a/packages/mcp-server/src/filtering.ts b/packages/mcp-server/src/filtering.ts index e560736..87eab2d 100644 --- a/packages/mcp-server/src/filtering.ts +++ b/packages/mcp-server/src/filtering.ts @@ -1,3 +1,6 @@ +// @ts-nocheck +import initJq from 'jq-web'; + export async function maybeFilter(args: Record | undefined, response: any): Promise { const jqFilter = args?.['jq_filter']; if (jqFilter && typeof jqFilter === 'string') { @@ -7,7 +10,6 @@ export async function maybeFilter(args: Record | undefined, res } } -var jqWeb = require('jq-web'); async function jq(json: any, jqFilter: string) { - return (await jqWeb).json(json, jqFilter); + return (await initJq).json(json, jqFilter); } From df24a2f821d16e2ef006bf6715be5d87b1179a83 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 16 Jul 2025 04:07:37 +0000 Subject: [PATCH 55/91] chore(mcp): rework imports in tools --- packages/mcp-server/src/tools/events/list-events.ts | 3 +-- packages/mcp-server/src/tools/files/delete-files.ts | 3 +-- packages/mcp-server/src/tools/files/download-files.ts | 3 +-- packages/mcp-server/src/tools/files/list-files.ts | 3 +-- packages/mcp-server/src/tools/files/retrieve-files.ts | 3 +-- packages/mcp-server/src/tools/files/upload-files.ts | 3 +-- .../tools/image-operations/apply-effect-image-operations.ts | 3 +-- .../src/tools/image-operations/convert-image-operations.ts | 3 +-- .../image-operations/detect-documents-image-operations.ts | 3 +-- .../tools/image-operations/extract-text-image-operations.ts | 3 +-- .../src/tools/image-operations/scan-image-operations.ts | 3 +-- .../src/tools/image-operations/warp-image-operations.ts | 3 +-- .../src/tools/pdf-operations/extract-pages-pdf-operations.ts | 3 +-- .../src/tools/pdf-operations/merge-pdf-operations.ts | 3 +-- .../src/tools/pdf-operations/render-pdf-operations.ts | 3 +-- .../src/tools/pdf-operations/split-pdf-operations.ts | 3 +-- packages/mcp-server/src/tools/tasks/list-tasks.ts | 3 +-- packages/mcp-server/src/tools/tasks/retrieve-tasks.ts | 3 +-- 18 files changed, 18 insertions(+), 36 deletions(-) diff --git a/packages/mcp-server/src/tools/events/list-events.ts b/packages/mcp-server/src/tools/events/list-events.ts index 41dc193..021c68d 100644 --- a/packages/mcp-server/src/tools/events/list-events.ts +++ b/packages/mcp-server/src/tools/events/list-events.ts @@ -1,9 +1,8 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { asTextContentResult } from 'scan-documents-mcp/tools/types'; +import { Metadata, asTextContentResult } from 'scan-documents-mcp/tools/types'; import { Tool } from '@modelcontextprotocol/sdk/types.js'; -import type { Metadata } from '../'; import ScanDocuments from 'scan-documents'; export const metadata: Metadata = { diff --git a/packages/mcp-server/src/tools/files/delete-files.ts b/packages/mcp-server/src/tools/files/delete-files.ts index ba194a2..db7b481 100644 --- a/packages/mcp-server/src/tools/files/delete-files.ts +++ b/packages/mcp-server/src/tools/files/delete-files.ts @@ -1,9 +1,8 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { asTextContentResult } from 'scan-documents-mcp/tools/types'; +import { Metadata, asTextContentResult } from 'scan-documents-mcp/tools/types'; import { Tool } from '@modelcontextprotocol/sdk/types.js'; -import type { Metadata } from '../'; import ScanDocuments from 'scan-documents'; export const metadata: Metadata = { diff --git a/packages/mcp-server/src/tools/files/download-files.ts b/packages/mcp-server/src/tools/files/download-files.ts index 56c785e..a5702a3 100644 --- a/packages/mcp-server/src/tools/files/download-files.ts +++ b/packages/mcp-server/src/tools/files/download-files.ts @@ -1,9 +1,8 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { asBinaryContentResult } from 'scan-documents-mcp/tools/types'; +import { Metadata, asBinaryContentResult } from 'scan-documents-mcp/tools/types'; import { Tool } from '@modelcontextprotocol/sdk/types.js'; -import type { Metadata } from '../'; import ScanDocuments from 'scan-documents'; export const metadata: Metadata = { diff --git a/packages/mcp-server/src/tools/files/list-files.ts b/packages/mcp-server/src/tools/files/list-files.ts index e9639fd..cd36d08 100644 --- a/packages/mcp-server/src/tools/files/list-files.ts +++ b/packages/mcp-server/src/tools/files/list-files.ts @@ -1,10 +1,9 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import { maybeFilter } from 'scan-documents-mcp/filtering'; -import { asTextContentResult } from 'scan-documents-mcp/tools/types'; +import { Metadata, asTextContentResult } from 'scan-documents-mcp/tools/types'; import { Tool } from '@modelcontextprotocol/sdk/types.js'; -import type { Metadata } from '../'; import ScanDocuments from 'scan-documents'; export const metadata: Metadata = { diff --git a/packages/mcp-server/src/tools/files/retrieve-files.ts b/packages/mcp-server/src/tools/files/retrieve-files.ts index be49d1d..2a21530 100644 --- a/packages/mcp-server/src/tools/files/retrieve-files.ts +++ b/packages/mcp-server/src/tools/files/retrieve-files.ts @@ -1,10 +1,9 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import { maybeFilter } from 'scan-documents-mcp/filtering'; -import { asTextContentResult } from 'scan-documents-mcp/tools/types'; +import { Metadata, asTextContentResult } from 'scan-documents-mcp/tools/types'; import { Tool } from '@modelcontextprotocol/sdk/types.js'; -import type { Metadata } from '../'; import ScanDocuments from 'scan-documents'; export const metadata: Metadata = { diff --git a/packages/mcp-server/src/tools/files/upload-files.ts b/packages/mcp-server/src/tools/files/upload-files.ts index 87635a9..56313f7 100644 --- a/packages/mcp-server/src/tools/files/upload-files.ts +++ b/packages/mcp-server/src/tools/files/upload-files.ts @@ -1,10 +1,9 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import { maybeFilter } from 'scan-documents-mcp/filtering'; -import { asTextContentResult } from 'scan-documents-mcp/tools/types'; +import { Metadata, asTextContentResult } from 'scan-documents-mcp/tools/types'; import { Tool } from '@modelcontextprotocol/sdk/types.js'; -import type { Metadata } from '../'; import ScanDocuments from 'scan-documents'; export const metadata: Metadata = { diff --git a/packages/mcp-server/src/tools/image-operations/apply-effect-image-operations.ts b/packages/mcp-server/src/tools/image-operations/apply-effect-image-operations.ts index c8f14b4..358edef 100644 --- a/packages/mcp-server/src/tools/image-operations/apply-effect-image-operations.ts +++ b/packages/mcp-server/src/tools/image-operations/apply-effect-image-operations.ts @@ -1,9 +1,8 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { asTextContentResult } from 'scan-documents-mcp/tools/types'; +import { Metadata, asTextContentResult } from 'scan-documents-mcp/tools/types'; import { Tool } from '@modelcontextprotocol/sdk/types.js'; -import type { Metadata } from '../'; import ScanDocuments from 'scan-documents'; export const metadata: Metadata = { diff --git a/packages/mcp-server/src/tools/image-operations/convert-image-operations.ts b/packages/mcp-server/src/tools/image-operations/convert-image-operations.ts index 28ed554..0aa401f 100644 --- a/packages/mcp-server/src/tools/image-operations/convert-image-operations.ts +++ b/packages/mcp-server/src/tools/image-operations/convert-image-operations.ts @@ -1,9 +1,8 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { asTextContentResult } from 'scan-documents-mcp/tools/types'; +import { Metadata, asTextContentResult } from 'scan-documents-mcp/tools/types'; import { Tool } from '@modelcontextprotocol/sdk/types.js'; -import type { Metadata } from '../'; import ScanDocuments from 'scan-documents'; export const metadata: Metadata = { diff --git a/packages/mcp-server/src/tools/image-operations/detect-documents-image-operations.ts b/packages/mcp-server/src/tools/image-operations/detect-documents-image-operations.ts index 4716107..531e118 100644 --- a/packages/mcp-server/src/tools/image-operations/detect-documents-image-operations.ts +++ b/packages/mcp-server/src/tools/image-operations/detect-documents-image-operations.ts @@ -1,9 +1,8 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { asTextContentResult } from 'scan-documents-mcp/tools/types'; +import { Metadata, asTextContentResult } from 'scan-documents-mcp/tools/types'; import { Tool } from '@modelcontextprotocol/sdk/types.js'; -import type { Metadata } from '../'; import ScanDocuments from 'scan-documents'; export const metadata: Metadata = { diff --git a/packages/mcp-server/src/tools/image-operations/extract-text-image-operations.ts b/packages/mcp-server/src/tools/image-operations/extract-text-image-operations.ts index 7577f29..c9d1a0a 100644 --- a/packages/mcp-server/src/tools/image-operations/extract-text-image-operations.ts +++ b/packages/mcp-server/src/tools/image-operations/extract-text-image-operations.ts @@ -1,9 +1,8 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { asTextContentResult } from 'scan-documents-mcp/tools/types'; +import { Metadata, asTextContentResult } from 'scan-documents-mcp/tools/types'; import { Tool } from '@modelcontextprotocol/sdk/types.js'; -import type { Metadata } from '../'; import ScanDocuments from 'scan-documents'; export const metadata: Metadata = { diff --git a/packages/mcp-server/src/tools/image-operations/scan-image-operations.ts b/packages/mcp-server/src/tools/image-operations/scan-image-operations.ts index ef68b47..0263c71 100644 --- a/packages/mcp-server/src/tools/image-operations/scan-image-operations.ts +++ b/packages/mcp-server/src/tools/image-operations/scan-image-operations.ts @@ -1,9 +1,8 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { asTextContentResult } from 'scan-documents-mcp/tools/types'; +import { Metadata, asTextContentResult } from 'scan-documents-mcp/tools/types'; import { Tool } from '@modelcontextprotocol/sdk/types.js'; -import type { Metadata } from '../'; import ScanDocuments from 'scan-documents'; export const metadata: Metadata = { diff --git a/packages/mcp-server/src/tools/image-operations/warp-image-operations.ts b/packages/mcp-server/src/tools/image-operations/warp-image-operations.ts index f3f5143..3d30b81 100644 --- a/packages/mcp-server/src/tools/image-operations/warp-image-operations.ts +++ b/packages/mcp-server/src/tools/image-operations/warp-image-operations.ts @@ -1,9 +1,8 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { asTextContentResult } from 'scan-documents-mcp/tools/types'; +import { Metadata, asTextContentResult } from 'scan-documents-mcp/tools/types'; import { Tool } from '@modelcontextprotocol/sdk/types.js'; -import type { Metadata } from '../'; import ScanDocuments from 'scan-documents'; export const metadata: Metadata = { diff --git a/packages/mcp-server/src/tools/pdf-operations/extract-pages-pdf-operations.ts b/packages/mcp-server/src/tools/pdf-operations/extract-pages-pdf-operations.ts index 36c41f6..4918610 100644 --- a/packages/mcp-server/src/tools/pdf-operations/extract-pages-pdf-operations.ts +++ b/packages/mcp-server/src/tools/pdf-operations/extract-pages-pdf-operations.ts @@ -1,9 +1,8 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { asTextContentResult } from 'scan-documents-mcp/tools/types'; +import { Metadata, asTextContentResult } from 'scan-documents-mcp/tools/types'; import { Tool } from '@modelcontextprotocol/sdk/types.js'; -import type { Metadata } from '../'; import ScanDocuments from 'scan-documents'; export const metadata: Metadata = { diff --git a/packages/mcp-server/src/tools/pdf-operations/merge-pdf-operations.ts b/packages/mcp-server/src/tools/pdf-operations/merge-pdf-operations.ts index d75296d..04778d5 100644 --- a/packages/mcp-server/src/tools/pdf-operations/merge-pdf-operations.ts +++ b/packages/mcp-server/src/tools/pdf-operations/merge-pdf-operations.ts @@ -1,9 +1,8 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { asTextContentResult } from 'scan-documents-mcp/tools/types'; +import { Metadata, asTextContentResult } from 'scan-documents-mcp/tools/types'; import { Tool } from '@modelcontextprotocol/sdk/types.js'; -import type { Metadata } from '../'; import ScanDocuments from 'scan-documents'; export const metadata: Metadata = { diff --git a/packages/mcp-server/src/tools/pdf-operations/render-pdf-operations.ts b/packages/mcp-server/src/tools/pdf-operations/render-pdf-operations.ts index 73ec49e..68862d4 100644 --- a/packages/mcp-server/src/tools/pdf-operations/render-pdf-operations.ts +++ b/packages/mcp-server/src/tools/pdf-operations/render-pdf-operations.ts @@ -1,9 +1,8 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { asTextContentResult } from 'scan-documents-mcp/tools/types'; +import { Metadata, asTextContentResult } from 'scan-documents-mcp/tools/types'; import { Tool } from '@modelcontextprotocol/sdk/types.js'; -import type { Metadata } from '../'; import ScanDocuments from 'scan-documents'; export const metadata: Metadata = { diff --git a/packages/mcp-server/src/tools/pdf-operations/split-pdf-operations.ts b/packages/mcp-server/src/tools/pdf-operations/split-pdf-operations.ts index cc305d8..609232c 100644 --- a/packages/mcp-server/src/tools/pdf-operations/split-pdf-operations.ts +++ b/packages/mcp-server/src/tools/pdf-operations/split-pdf-operations.ts @@ -1,9 +1,8 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { asTextContentResult } from 'scan-documents-mcp/tools/types'; +import { Metadata, asTextContentResult } from 'scan-documents-mcp/tools/types'; import { Tool } from '@modelcontextprotocol/sdk/types.js'; -import type { Metadata } from '../'; import ScanDocuments from 'scan-documents'; export const metadata: Metadata = { diff --git a/packages/mcp-server/src/tools/tasks/list-tasks.ts b/packages/mcp-server/src/tools/tasks/list-tasks.ts index 619abcd..59dd66f 100644 --- a/packages/mcp-server/src/tools/tasks/list-tasks.ts +++ b/packages/mcp-server/src/tools/tasks/list-tasks.ts @@ -1,9 +1,8 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { asTextContentResult } from 'scan-documents-mcp/tools/types'; +import { Metadata, asTextContentResult } from 'scan-documents-mcp/tools/types'; import { Tool } from '@modelcontextprotocol/sdk/types.js'; -import type { Metadata } from '../'; import ScanDocuments from 'scan-documents'; export const metadata: Metadata = { diff --git a/packages/mcp-server/src/tools/tasks/retrieve-tasks.ts b/packages/mcp-server/src/tools/tasks/retrieve-tasks.ts index 2b559b3..a077ad1 100644 --- a/packages/mcp-server/src/tools/tasks/retrieve-tasks.ts +++ b/packages/mcp-server/src/tools/tasks/retrieve-tasks.ts @@ -1,9 +1,8 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { asTextContentResult } from 'scan-documents-mcp/tools/types'; +import { Metadata, asTextContentResult } from 'scan-documents-mcp/tools/types'; import { Tool } from '@modelcontextprotocol/sdk/types.js'; -import type { Metadata } from '../'; import ScanDocuments from 'scan-documents'; export const metadata: Metadata = { From 596fc4f6d1323ceeecf8eef62cc165d5430f9069 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 17 Jul 2025 03:05:59 +0000 Subject: [PATCH 56/91] chore(ts): reorder package.json imports --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index f3fe912..8b85811 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,6 @@ "@swc/jest": "^0.2.29", "@types/jest": "^29.4.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", @@ -44,7 +43,8 @@ "ts-node": "^10.5.0", "tsc-multi": "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.8/tsc-multi.tgz", "tsconfig-paths": "^4.0.0", - "typescript": "5.8.3" + "typescript": "5.8.3", + "typescript-eslint": "8.31.1" }, "imports": { "scan-documents": ".", From 32923a200bbe8c6ba2658428be044bd14e5f09cb Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 17 Jul 2025 03:26:08 +0000 Subject: [PATCH 57/91] chore(mcp): formatting --- packages/mcp-server/src/server.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/mcp-server/src/server.ts b/packages/mcp-server/src/server.ts index fa19ef1..6003f4a 100644 --- a/packages/mcp-server/src/server.ts +++ b/packages/mcp-server/src/server.ts @@ -28,11 +28,7 @@ export const server = new McpServer( name: 'scan_documents_api', version: '0.1.0-alpha.5', }, - { - capabilities: { - tools: {}, - }, - }, + { capabilities: { tools: {} } }, ); /** From f7827a6390ec0922cdc039344f47774cf588da14 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 18 Jul 2025 03:05:22 +0000 Subject: [PATCH 58/91] fix(mcp): include required section for top-level properties and support naming transformations --- packages/mcp-server/src/tools/events/list-events.ts | 1 + packages/mcp-server/src/tools/files/delete-files.ts | 1 + packages/mcp-server/src/tools/files/download-files.ts | 1 + packages/mcp-server/src/tools/files/list-files.ts | 1 + packages/mcp-server/src/tools/files/retrieve-files.ts | 1 + packages/mcp-server/src/tools/files/upload-files.ts | 1 + .../tools/image-operations/apply-effect-image-operations.ts | 1 + .../src/tools/image-operations/convert-image-operations.ts | 3 +++ .../image-operations/detect-documents-image-operations.ts | 1 + .../tools/image-operations/extract-text-image-operations.ts | 5 ++++- .../src/tools/image-operations/scan-image-operations.ts | 1 + .../src/tools/image-operations/warp-image-operations.ts | 1 + .../src/tools/pdf-operations/extract-pages-pdf-operations.ts | 1 + .../src/tools/pdf-operations/merge-pdf-operations.ts | 1 + .../src/tools/pdf-operations/render-pdf-operations.ts | 1 + .../src/tools/pdf-operations/split-pdf-operations.ts | 1 + packages/mcp-server/src/tools/tasks/list-tasks.ts | 1 + packages/mcp-server/src/tools/tasks/retrieve-tasks.ts | 1 + 18 files changed, 23 insertions(+), 1 deletion(-) diff --git a/packages/mcp-server/src/tools/events/list-events.ts b/packages/mcp-server/src/tools/events/list-events.ts index 021c68d..441646f 100644 --- a/packages/mcp-server/src/tools/events/list-events.ts +++ b/packages/mcp-server/src/tools/events/list-events.ts @@ -28,6 +28,7 @@ export const tool: Tool = { type: 'number', }, }, + required: [], }, }; diff --git a/packages/mcp-server/src/tools/files/delete-files.ts b/packages/mcp-server/src/tools/files/delete-files.ts index db7b481..9b10a7e 100644 --- a/packages/mcp-server/src/tools/files/delete-files.ts +++ b/packages/mcp-server/src/tools/files/delete-files.ts @@ -31,6 +31,7 @@ export const tool: Tool = { 'A jq filter to apply to the response to include certain fields. Consult the output schema in the tool description to see the fields that are available.\n\nFor example: to include only the `name` field in every object of a results array, you can provide ".results[].name".\n\nFor more information, see the [jq documentation](https://jqlang.org/manual/).', }, }, + required: ['id'], }, }; diff --git a/packages/mcp-server/src/tools/files/download-files.ts b/packages/mcp-server/src/tools/files/download-files.ts index a5702a3..a50ae21 100644 --- a/packages/mcp-server/src/tools/files/download-files.ts +++ b/packages/mcp-server/src/tools/files/download-files.ts @@ -31,6 +31,7 @@ export const tool: Tool = { 'A jq filter to apply to the response to include certain fields. Consult the output schema in the tool description to see the fields that are available.\n\nFor example: to include only the `name` field in every object of a results array, you can provide ".results[].name".\n\nFor more information, see the [jq documentation](https://jqlang.org/manual/).', }, }, + required: ['id'], }, }; diff --git a/packages/mcp-server/src/tools/files/list-files.ts b/packages/mcp-server/src/tools/files/list-files.ts index cd36d08..64a165e 100644 --- a/packages/mcp-server/src/tools/files/list-files.ts +++ b/packages/mcp-server/src/tools/files/list-files.ts @@ -37,6 +37,7 @@ export const tool: Tool = { 'A jq filter to apply to the response to include certain fields. Consult the output schema in the tool description to see the fields that are available.\n\nFor example: to include only the `name` field in every object of a results array, you can provide ".results[].name".\n\nFor more information, see the [jq documentation](https://jqlang.org/manual/).', }, }, + required: [], }, }; diff --git a/packages/mcp-server/src/tools/files/retrieve-files.ts b/packages/mcp-server/src/tools/files/retrieve-files.ts index 2a21530..486535c 100644 --- a/packages/mcp-server/src/tools/files/retrieve-files.ts +++ b/packages/mcp-server/src/tools/files/retrieve-files.ts @@ -32,6 +32,7 @@ export const tool: Tool = { 'A jq filter to apply to the response to include certain fields. Consult the output schema in the tool description to see the fields that are available.\n\nFor example: to include only the `name` field in every object of a results array, you can provide ".results[].name".\n\nFor more information, see the [jq documentation](https://jqlang.org/manual/).', }, }, + required: ['id'], }, }; diff --git a/packages/mcp-server/src/tools/files/upload-files.ts b/packages/mcp-server/src/tools/files/upload-files.ts index 56313f7..0722ac5 100644 --- a/packages/mcp-server/src/tools/files/upload-files.ts +++ b/packages/mcp-server/src/tools/files/upload-files.ts @@ -37,6 +37,7 @@ export const tool: Tool = { 'A jq filter to apply to the response to include certain fields. Consult the output schema in the tool description to see the fields that are available.\n\nFor example: to include only the `name` field in every object of a results array, you can provide ".results[].name".\n\nFor more information, see the [jq documentation](https://jqlang.org/manual/).', }, }, + required: ['file', 'name'], }, }; diff --git a/packages/mcp-server/src/tools/image-operations/apply-effect-image-operations.ts b/packages/mcp-server/src/tools/image-operations/apply-effect-image-operations.ts index 358edef..f53d36c 100644 --- a/packages/mcp-server/src/tools/image-operations/apply-effect-image-operations.ts +++ b/packages/mcp-server/src/tools/image-operations/apply-effect-image-operations.ts @@ -40,6 +40,7 @@ export const tool: Tool = { description: 'The name of the file', }, }, + required: ['effect', 'input'], }, }; diff --git a/packages/mcp-server/src/tools/image-operations/convert-image-operations.ts b/packages/mcp-server/src/tools/image-operations/convert-image-operations.ts index 0aa401f..cbd138e 100644 --- a/packages/mcp-server/src/tools/image-operations/convert-image-operations.ts +++ b/packages/mcp-server/src/tools/image-operations/convert-image-operations.ts @@ -43,6 +43,7 @@ export const tool: Tool = { description: 'The name of the file', }, }, + required: ['input', 'target_format'], }, { type: 'object', @@ -70,6 +71,7 @@ export const tool: Tool = { description: 'The name of the file', }, }, + required: ['input', 'quality', 'target_format'], }, { type: 'object', @@ -97,6 +99,7 @@ export const tool: Tool = { description: 'The name of the file', }, }, + required: ['input', 'quality', 'target_format'], }, ], }, diff --git a/packages/mcp-server/src/tools/image-operations/detect-documents-image-operations.ts b/packages/mcp-server/src/tools/image-operations/detect-documents-image-operations.ts index 531e118..b27e639 100644 --- a/packages/mcp-server/src/tools/image-operations/detect-documents-image-operations.ts +++ b/packages/mcp-server/src/tools/image-operations/detect-documents-image-operations.ts @@ -31,6 +31,7 @@ export const tool: Tool = { 'The URL to call when the task is completed or failed. If you want to receive events, you probably prefer to use `webhooks` instead.', }, }, + required: ['input'], }, }; diff --git a/packages/mcp-server/src/tools/image-operations/extract-text-image-operations.ts b/packages/mcp-server/src/tools/image-operations/extract-text-image-operations.ts index c9d1a0a..778dac3 100644 --- a/packages/mcp-server/src/tools/image-operations/extract-text-image-operations.ts +++ b/packages/mcp-server/src/tools/image-operations/extract-text-image-operations.ts @@ -39,6 +39,7 @@ export const tool: Tool = { 'The URL to call when the task is completed or failed. If you want to receive events, you probably prefer to use `webhooks` instead.', }, }, + required: ['format', 'input'], }, { type: 'object', @@ -58,6 +59,7 @@ export const tool: Tool = { 'The URL to call when the task is completed or failed. If you want to receive events, you probably prefer to use `webhooks` instead.', }, }, + required: ['format', 'input'], }, { type: 'object', @@ -77,6 +79,7 @@ export const tool: Tool = { 'The URL to call when the task is completed or failed. If you want to receive events, you probably prefer to use `webhooks` instead.', }, }, + required: ['format', 'input'], }, { type: 'object', @@ -99,6 +102,7 @@ export const tool: Tool = { 'The URL to call when the task is completed or failed. If you want to receive events, you probably prefer to use `webhooks` instead.', }, }, + required: ['format', 'input', 'schema'], }, ], $defs: { @@ -133,7 +137,6 @@ export const tool: Tool = { enum: ['string', 'number', 'integer', 'boolean', 'array', 'object'], }, }, - required: [], }, }, }, diff --git a/packages/mcp-server/src/tools/image-operations/scan-image-operations.ts b/packages/mcp-server/src/tools/image-operations/scan-image-operations.ts index 0263c71..a0aa629 100644 --- a/packages/mcp-server/src/tools/image-operations/scan-image-operations.ts +++ b/packages/mcp-server/src/tools/image-operations/scan-image-operations.ts @@ -46,6 +46,7 @@ export const tool: Tool = { description: 'The name of the file', }, }, + required: ['effect', 'input', 'scan_mode'], }, }; diff --git a/packages/mcp-server/src/tools/image-operations/warp-image-operations.ts b/packages/mcp-server/src/tools/image-operations/warp-image-operations.ts index 3d30b81..ba41aaf 100644 --- a/packages/mcp-server/src/tools/image-operations/warp-image-operations.ts +++ b/packages/mcp-server/src/tools/image-operations/warp-image-operations.ts @@ -42,6 +42,7 @@ export const tool: Tool = { description: 'The name of the file', }, }, + required: ['input', 'vertices'], }, }; diff --git a/packages/mcp-server/src/tools/pdf-operations/extract-pages-pdf-operations.ts b/packages/mcp-server/src/tools/pdf-operations/extract-pages-pdf-operations.ts index 4918610..814e688 100644 --- a/packages/mcp-server/src/tools/pdf-operations/extract-pages-pdf-operations.ts +++ b/packages/mcp-server/src/tools/pdf-operations/extract-pages-pdf-operations.ts @@ -39,6 +39,7 @@ export const tool: Tool = { description: 'The name of the file', }, }, + required: ['input', 'pages'], }, }; diff --git a/packages/mcp-server/src/tools/pdf-operations/merge-pdf-operations.ts b/packages/mcp-server/src/tools/pdf-operations/merge-pdf-operations.ts index 04778d5..fc902c3 100644 --- a/packages/mcp-server/src/tools/pdf-operations/merge-pdf-operations.ts +++ b/packages/mcp-server/src/tools/pdf-operations/merge-pdf-operations.ts @@ -39,6 +39,7 @@ export const tool: Tool = { description: 'The name of the file', }, }, + required: ['input'], }, }; diff --git a/packages/mcp-server/src/tools/pdf-operations/render-pdf-operations.ts b/packages/mcp-server/src/tools/pdf-operations/render-pdf-operations.ts index 68862d4..890b30b 100644 --- a/packages/mcp-server/src/tools/pdf-operations/render-pdf-operations.ts +++ b/packages/mcp-server/src/tools/pdf-operations/render-pdf-operations.ts @@ -43,6 +43,7 @@ export const tool: Tool = { description: 'Page range (e.g., 2-7), a comma-separated list (e.g., 2,3,7) of pages.', }, }, + required: ['input'], }, }; diff --git a/packages/mcp-server/src/tools/pdf-operations/split-pdf-operations.ts b/packages/mcp-server/src/tools/pdf-operations/split-pdf-operations.ts index 609232c..957ddea 100644 --- a/packages/mcp-server/src/tools/pdf-operations/split-pdf-operations.ts +++ b/packages/mcp-server/src/tools/pdf-operations/split-pdf-operations.ts @@ -35,6 +35,7 @@ export const tool: Tool = { description: 'The name of the file', }, }, + required: ['input'], }, }; diff --git a/packages/mcp-server/src/tools/tasks/list-tasks.ts b/packages/mcp-server/src/tools/tasks/list-tasks.ts index 59dd66f..d89753a 100644 --- a/packages/mcp-server/src/tools/tasks/list-tasks.ts +++ b/packages/mcp-server/src/tools/tasks/list-tasks.ts @@ -28,6 +28,7 @@ export const tool: Tool = { type: 'number', }, }, + required: [], }, }; diff --git a/packages/mcp-server/src/tools/tasks/retrieve-tasks.ts b/packages/mcp-server/src/tools/tasks/retrieve-tasks.ts index a077ad1..6924f18 100644 --- a/packages/mcp-server/src/tools/tasks/retrieve-tasks.ts +++ b/packages/mcp-server/src/tools/tasks/retrieve-tasks.ts @@ -26,6 +26,7 @@ export const tool: Tool = { description: 'The id of the task to get.', }, }, + required: ['id'], }, }; From b47458d7c6269e4acbfc6fb4b469597581633e49 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 24 Jul 2025 03:48:44 +0000 Subject: [PATCH 59/91] chore(internal): codegen related update --- packages/mcp-server/src/tools/events/list-events.ts | 3 +++ packages/mcp-server/src/tools/files/delete-files.ts | 3 +++ packages/mcp-server/src/tools/files/download-files.ts | 3 +++ packages/mcp-server/src/tools/files/list-files.ts | 3 +++ packages/mcp-server/src/tools/files/retrieve-files.ts | 3 +++ packages/mcp-server/src/tools/files/upload-files.ts | 1 + .../tools/image-operations/apply-effect-image-operations.ts | 1 + .../src/tools/image-operations/convert-image-operations.ts | 1 + .../image-operations/detect-documents-image-operations.ts | 1 + .../tools/image-operations/extract-text-image-operations.ts | 1 + .../src/tools/image-operations/scan-image-operations.ts | 1 + .../src/tools/image-operations/warp-image-operations.ts | 1 + .../src/tools/pdf-operations/extract-pages-pdf-operations.ts | 1 + .../src/tools/pdf-operations/merge-pdf-operations.ts | 1 + .../src/tools/pdf-operations/render-pdf-operations.ts | 1 + .../src/tools/pdf-operations/split-pdf-operations.ts | 1 + packages/mcp-server/src/tools/tasks/list-tasks.ts | 3 +++ packages/mcp-server/src/tools/tasks/retrieve-tasks.ts | 3 +++ 18 files changed, 32 insertions(+) diff --git a/packages/mcp-server/src/tools/events/list-events.ts b/packages/mcp-server/src/tools/events/list-events.ts index 441646f..559c6db 100644 --- a/packages/mcp-server/src/tools/events/list-events.ts +++ b/packages/mcp-server/src/tools/events/list-events.ts @@ -30,6 +30,9 @@ export const tool: Tool = { }, required: [], }, + annotations: { + readOnlyHint: true, + }, }; export const handler = async (client: ScanDocuments, args: Record | undefined) => { diff --git a/packages/mcp-server/src/tools/files/delete-files.ts b/packages/mcp-server/src/tools/files/delete-files.ts index 9b10a7e..b080708 100644 --- a/packages/mcp-server/src/tools/files/delete-files.ts +++ b/packages/mcp-server/src/tools/files/delete-files.ts @@ -33,6 +33,9 @@ export const tool: Tool = { }, required: ['id'], }, + annotations: { + idempotentHint: true, + }, }; export const handler = async (client: ScanDocuments, args: Record | undefined) => { diff --git a/packages/mcp-server/src/tools/files/download-files.ts b/packages/mcp-server/src/tools/files/download-files.ts index a50ae21..5c3951f 100644 --- a/packages/mcp-server/src/tools/files/download-files.ts +++ b/packages/mcp-server/src/tools/files/download-files.ts @@ -33,6 +33,9 @@ export const tool: Tool = { }, required: ['id'], }, + annotations: { + readOnlyHint: true, + }, }; export const handler = async (client: ScanDocuments, args: Record | undefined) => { diff --git a/packages/mcp-server/src/tools/files/list-files.ts b/packages/mcp-server/src/tools/files/list-files.ts index 64a165e..8d80803 100644 --- a/packages/mcp-server/src/tools/files/list-files.ts +++ b/packages/mcp-server/src/tools/files/list-files.ts @@ -39,6 +39,9 @@ export const tool: Tool = { }, required: [], }, + annotations: { + readOnlyHint: true, + }, }; export const handler = async (client: ScanDocuments, args: Record | undefined) => { diff --git a/packages/mcp-server/src/tools/files/retrieve-files.ts b/packages/mcp-server/src/tools/files/retrieve-files.ts index 486535c..10223c9 100644 --- a/packages/mcp-server/src/tools/files/retrieve-files.ts +++ b/packages/mcp-server/src/tools/files/retrieve-files.ts @@ -34,6 +34,9 @@ export const tool: Tool = { }, required: ['id'], }, + annotations: { + readOnlyHint: true, + }, }; export const handler = async (client: ScanDocuments, args: Record | undefined) => { diff --git a/packages/mcp-server/src/tools/files/upload-files.ts b/packages/mcp-server/src/tools/files/upload-files.ts index 0722ac5..5bb64e2 100644 --- a/packages/mcp-server/src/tools/files/upload-files.ts +++ b/packages/mcp-server/src/tools/files/upload-files.ts @@ -39,6 +39,7 @@ export const tool: Tool = { }, required: ['file', 'name'], }, + annotations: {}, }; export const handler = async (client: ScanDocuments, args: Record | undefined) => { diff --git a/packages/mcp-server/src/tools/image-operations/apply-effect-image-operations.ts b/packages/mcp-server/src/tools/image-operations/apply-effect-image-operations.ts index f53d36c..c616c8b 100644 --- a/packages/mcp-server/src/tools/image-operations/apply-effect-image-operations.ts +++ b/packages/mcp-server/src/tools/image-operations/apply-effect-image-operations.ts @@ -42,6 +42,7 @@ export const tool: Tool = { }, required: ['effect', 'input'], }, + annotations: {}, }; export const handler = async (client: ScanDocuments, args: Record | undefined) => { diff --git a/packages/mcp-server/src/tools/image-operations/convert-image-operations.ts b/packages/mcp-server/src/tools/image-operations/convert-image-operations.ts index cbd138e..81d4748 100644 --- a/packages/mcp-server/src/tools/image-operations/convert-image-operations.ts +++ b/packages/mcp-server/src/tools/image-operations/convert-image-operations.ts @@ -103,6 +103,7 @@ export const tool: Tool = { }, ], }, + annotations: {}, }; export const handler = async (client: ScanDocuments, args: Record | undefined) => { diff --git a/packages/mcp-server/src/tools/image-operations/detect-documents-image-operations.ts b/packages/mcp-server/src/tools/image-operations/detect-documents-image-operations.ts index b27e639..e175ef8 100644 --- a/packages/mcp-server/src/tools/image-operations/detect-documents-image-operations.ts +++ b/packages/mcp-server/src/tools/image-operations/detect-documents-image-operations.ts @@ -33,6 +33,7 @@ export const tool: Tool = { }, required: ['input'], }, + annotations: {}, }; export const handler = async (client: ScanDocuments, args: Record | undefined) => { diff --git a/packages/mcp-server/src/tools/image-operations/extract-text-image-operations.ts b/packages/mcp-server/src/tools/image-operations/extract-text-image-operations.ts index 778dac3..e742d7c 100644 --- a/packages/mcp-server/src/tools/image-operations/extract-text-image-operations.ts +++ b/packages/mcp-server/src/tools/image-operations/extract-text-image-operations.ts @@ -140,6 +140,7 @@ export const tool: Tool = { }, }, }, + annotations: {}, }; export const handler = async (client: ScanDocuments, args: Record | undefined) => { diff --git a/packages/mcp-server/src/tools/image-operations/scan-image-operations.ts b/packages/mcp-server/src/tools/image-operations/scan-image-operations.ts index a0aa629..606c00c 100644 --- a/packages/mcp-server/src/tools/image-operations/scan-image-operations.ts +++ b/packages/mcp-server/src/tools/image-operations/scan-image-operations.ts @@ -48,6 +48,7 @@ export const tool: Tool = { }, required: ['effect', 'input', 'scan_mode'], }, + annotations: {}, }; export const handler = async (client: ScanDocuments, args: Record | undefined) => { diff --git a/packages/mcp-server/src/tools/image-operations/warp-image-operations.ts b/packages/mcp-server/src/tools/image-operations/warp-image-operations.ts index ba41aaf..4221f9f 100644 --- a/packages/mcp-server/src/tools/image-operations/warp-image-operations.ts +++ b/packages/mcp-server/src/tools/image-operations/warp-image-operations.ts @@ -44,6 +44,7 @@ export const tool: Tool = { }, required: ['input', 'vertices'], }, + annotations: {}, }; export const handler = async (client: ScanDocuments, args: Record | undefined) => { diff --git a/packages/mcp-server/src/tools/pdf-operations/extract-pages-pdf-operations.ts b/packages/mcp-server/src/tools/pdf-operations/extract-pages-pdf-operations.ts index 814e688..238a397 100644 --- a/packages/mcp-server/src/tools/pdf-operations/extract-pages-pdf-operations.ts +++ b/packages/mcp-server/src/tools/pdf-operations/extract-pages-pdf-operations.ts @@ -41,6 +41,7 @@ export const tool: Tool = { }, required: ['input', 'pages'], }, + annotations: {}, }; export const handler = async (client: ScanDocuments, args: Record | undefined) => { diff --git a/packages/mcp-server/src/tools/pdf-operations/merge-pdf-operations.ts b/packages/mcp-server/src/tools/pdf-operations/merge-pdf-operations.ts index fc902c3..f149056 100644 --- a/packages/mcp-server/src/tools/pdf-operations/merge-pdf-operations.ts +++ b/packages/mcp-server/src/tools/pdf-operations/merge-pdf-operations.ts @@ -41,6 +41,7 @@ export const tool: Tool = { }, required: ['input'], }, + annotations: {}, }; export const handler = async (client: ScanDocuments, args: Record | undefined) => { diff --git a/packages/mcp-server/src/tools/pdf-operations/render-pdf-operations.ts b/packages/mcp-server/src/tools/pdf-operations/render-pdf-operations.ts index 890b30b..c53289a 100644 --- a/packages/mcp-server/src/tools/pdf-operations/render-pdf-operations.ts +++ b/packages/mcp-server/src/tools/pdf-operations/render-pdf-operations.ts @@ -45,6 +45,7 @@ export const tool: Tool = { }, required: ['input'], }, + annotations: {}, }; export const handler = async (client: ScanDocuments, args: Record | undefined) => { diff --git a/packages/mcp-server/src/tools/pdf-operations/split-pdf-operations.ts b/packages/mcp-server/src/tools/pdf-operations/split-pdf-operations.ts index 957ddea..1c8c6d2 100644 --- a/packages/mcp-server/src/tools/pdf-operations/split-pdf-operations.ts +++ b/packages/mcp-server/src/tools/pdf-operations/split-pdf-operations.ts @@ -37,6 +37,7 @@ export const tool: Tool = { }, required: ['input'], }, + annotations: {}, }; export const handler = async (client: ScanDocuments, args: Record | undefined) => { diff --git a/packages/mcp-server/src/tools/tasks/list-tasks.ts b/packages/mcp-server/src/tools/tasks/list-tasks.ts index d89753a..f8c3702 100644 --- a/packages/mcp-server/src/tools/tasks/list-tasks.ts +++ b/packages/mcp-server/src/tools/tasks/list-tasks.ts @@ -30,6 +30,9 @@ export const tool: Tool = { }, required: [], }, + annotations: { + readOnlyHint: true, + }, }; export const handler = async (client: ScanDocuments, args: Record | undefined) => { diff --git a/packages/mcp-server/src/tools/tasks/retrieve-tasks.ts b/packages/mcp-server/src/tools/tasks/retrieve-tasks.ts index 6924f18..8ea1147 100644 --- a/packages/mcp-server/src/tools/tasks/retrieve-tasks.ts +++ b/packages/mcp-server/src/tools/tasks/retrieve-tasks.ts @@ -28,6 +28,9 @@ export const tool: Tool = { }, required: ['id'], }, + annotations: { + readOnlyHint: true, + }, }; export const handler = async (client: ScanDocuments, args: Record | undefined) => { From cfe049c407230ed71a4216f893cedb1c85ba856e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 30 Jul 2025 04:30:00 +0000 Subject: [PATCH 60/91] chore(internal): remove redundant imports config --- package.json | 4 ---- 1 file changed, 4 deletions(-) diff --git a/package.json b/package.json index 8b85811..d87bc9e 100644 --- a/package.json +++ b/package.json @@ -46,10 +46,6 @@ "typescript": "5.8.3", "typescript-eslint": "8.31.1" }, - "imports": { - "scan-documents": ".", - "scan-documents/*": "./src/*" - }, "exports": { ".": { "import": "./dist/index.mjs", From 33effa6ccb54e2da65a9aaad00bcbb7070e2bdd0 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 31 Jul 2025 06:15:24 +0000 Subject: [PATCH 61/91] fix(mcp): fix tool description of jq_filter --- packages/mcp-server/src/tools/events/list-events.ts | 3 +-- .../tools/image-operations/apply-effect-image-operations.ts | 3 +-- .../src/tools/image-operations/convert-image-operations.ts | 3 +-- .../image-operations/detect-documents-image-operations.ts | 3 +-- .../tools/image-operations/extract-text-image-operations.ts | 3 +-- .../src/tools/image-operations/scan-image-operations.ts | 2 +- .../src/tools/image-operations/warp-image-operations.ts | 2 +- .../src/tools/pdf-operations/extract-pages-pdf-operations.ts | 3 +-- .../src/tools/pdf-operations/merge-pdf-operations.ts | 3 +-- .../src/tools/pdf-operations/render-pdf-operations.ts | 3 +-- .../src/tools/pdf-operations/split-pdf-operations.ts | 3 +-- packages/mcp-server/src/tools/tasks/list-tasks.ts | 3 +-- packages/mcp-server/src/tools/tasks/retrieve-tasks.ts | 3 +-- 13 files changed, 13 insertions(+), 24 deletions(-) diff --git a/packages/mcp-server/src/tools/events/list-events.ts b/packages/mcp-server/src/tools/events/list-events.ts index 559c6db..5cac1ae 100644 --- a/packages/mcp-server/src/tools/events/list-events.ts +++ b/packages/mcp-server/src/tools/events/list-events.ts @@ -16,8 +16,7 @@ export const metadata: Metadata = { export const tool: Tool = { name: 'list_events', - description: - "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nRetrieves a paginated list of events belonging to the authenticated user.", + description: 'Retrieves a paginated list of events belonging to the authenticated user.', inputSchema: { type: 'object', properties: { diff --git a/packages/mcp-server/src/tools/image-operations/apply-effect-image-operations.ts b/packages/mcp-server/src/tools/image-operations/apply-effect-image-operations.ts index c616c8b..70fce7c 100644 --- a/packages/mcp-server/src/tools/image-operations/apply-effect-image-operations.ts +++ b/packages/mcp-server/src/tools/image-operations/apply-effect-image-operations.ts @@ -16,8 +16,7 @@ export const metadata: Metadata = { export const tool: Tool = { name: 'apply_effect_image_operations', - description: - "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nCreates a task to apply a specified visual effect to an image.", + description: 'Creates a task to apply a specified visual effect to an image.', inputSchema: { type: 'object', properties: { diff --git a/packages/mcp-server/src/tools/image-operations/convert-image-operations.ts b/packages/mcp-server/src/tools/image-operations/convert-image-operations.ts index 81d4748..058d677 100644 --- a/packages/mcp-server/src/tools/image-operations/convert-image-operations.ts +++ b/packages/mcp-server/src/tools/image-operations/convert-image-operations.ts @@ -16,8 +16,7 @@ export const metadata: Metadata = { export const tool: Tool = { name: 'convert_image_operations', - description: - "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nCreates a task to convert an image file to a different format.", + description: 'Creates a task to convert an image file to a different format.', inputSchema: { type: 'object', anyOf: [ diff --git a/packages/mcp-server/src/tools/image-operations/detect-documents-image-operations.ts b/packages/mcp-server/src/tools/image-operations/detect-documents-image-operations.ts index e175ef8..274ca13 100644 --- a/packages/mcp-server/src/tools/image-operations/detect-documents-image-operations.ts +++ b/packages/mcp-server/src/tools/image-operations/detect-documents-image-operations.ts @@ -16,8 +16,7 @@ export const metadata: Metadata = { export const tool: Tool = { name: 'detect_documents_image_operations', - description: - "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nCreates a task to detect document boundaries within an image.", + description: 'Creates a task to detect document boundaries within an image.', inputSchema: { type: 'object', properties: { diff --git a/packages/mcp-server/src/tools/image-operations/extract-text-image-operations.ts b/packages/mcp-server/src/tools/image-operations/extract-text-image-operations.ts index e742d7c..cdb16c5 100644 --- a/packages/mcp-server/src/tools/image-operations/extract-text-image-operations.ts +++ b/packages/mcp-server/src/tools/image-operations/extract-text-image-operations.ts @@ -16,8 +16,7 @@ export const metadata: Metadata = { export const tool: Tool = { name: 'extract_text_image_operations', - description: - "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nCreates a task to extract text from a specified image file.", + description: 'Creates a task to extract text from a specified image file.', inputSchema: { type: 'object', anyOf: [ diff --git a/packages/mcp-server/src/tools/image-operations/scan-image-operations.ts b/packages/mcp-server/src/tools/image-operations/scan-image-operations.ts index 606c00c..4846e3c 100644 --- a/packages/mcp-server/src/tools/image-operations/scan-image-operations.ts +++ b/packages/mcp-server/src/tools/image-operations/scan-image-operations.ts @@ -17,7 +17,7 @@ export const metadata: Metadata = { export const tool: Tool = { name: 'scan_image_operations', description: - "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nCreates a task to scan an image file. \nThis is an equivalent operation for `detect-documents` and `warp` combined, additionally it can apply effects to the scanned image.", + 'Creates a task to scan an image file. \nThis is an equivalent operation for `detect-documents` and `warp` combined, additionally it can apply effects to the scanned image.', inputSchema: { type: 'object', properties: { diff --git a/packages/mcp-server/src/tools/image-operations/warp-image-operations.ts b/packages/mcp-server/src/tools/image-operations/warp-image-operations.ts index 4221f9f..c0ffe87 100644 --- a/packages/mcp-server/src/tools/image-operations/warp-image-operations.ts +++ b/packages/mcp-server/src/tools/image-operations/warp-image-operations.ts @@ -17,7 +17,7 @@ export const metadata: Metadata = { export const tool: Tool = { name: 'warp_image_operations', description: - "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nCreates a task to apply perspective correction (warp) to an image based on detected document boundaries.", + 'Creates a task to apply perspective correction (warp) to an image based on detected document boundaries.', inputSchema: { type: 'object', properties: { diff --git a/packages/mcp-server/src/tools/pdf-operations/extract-pages-pdf-operations.ts b/packages/mcp-server/src/tools/pdf-operations/extract-pages-pdf-operations.ts index 238a397..2f2d630 100644 --- a/packages/mcp-server/src/tools/pdf-operations/extract-pages-pdf-operations.ts +++ b/packages/mcp-server/src/tools/pdf-operations/extract-pages-pdf-operations.ts @@ -16,8 +16,7 @@ export const metadata: Metadata = { export const tool: Tool = { name: 'extract_pages_pdf_operations', - description: - "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nCreates a task to extract specific pages from a PDF file into a new PDF file.", + description: 'Creates a task to extract specific pages from a PDF file into a new PDF file.', inputSchema: { type: 'object', properties: { diff --git a/packages/mcp-server/src/tools/pdf-operations/merge-pdf-operations.ts b/packages/mcp-server/src/tools/pdf-operations/merge-pdf-operations.ts index f149056..343f025 100644 --- a/packages/mcp-server/src/tools/pdf-operations/merge-pdf-operations.ts +++ b/packages/mcp-server/src/tools/pdf-operations/merge-pdf-operations.ts @@ -16,8 +16,7 @@ export const metadata: Metadata = { export const tool: Tool = { name: 'merge_pdf_operations', - description: - "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nCreates a task to merge multiple PDF and/or image files into a single PDF file.", + description: 'Creates a task to merge multiple PDF and/or image files into a single PDF file.', inputSchema: { type: 'object', properties: { diff --git a/packages/mcp-server/src/tools/pdf-operations/render-pdf-operations.ts b/packages/mcp-server/src/tools/pdf-operations/render-pdf-operations.ts index c53289a..5dc6671 100644 --- a/packages/mcp-server/src/tools/pdf-operations/render-pdf-operations.ts +++ b/packages/mcp-server/src/tools/pdf-operations/render-pdf-operations.ts @@ -16,8 +16,7 @@ export const metadata: Metadata = { export const tool: Tool = { name: 'render_pdf_operations', - description: - "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nCreates a task to render specified pages of a PDF file as images.", + description: 'Creates a task to render specified pages of a PDF file as images.', inputSchema: { type: 'object', properties: { diff --git a/packages/mcp-server/src/tools/pdf-operations/split-pdf-operations.ts b/packages/mcp-server/src/tools/pdf-operations/split-pdf-operations.ts index 1c8c6d2..4d77190 100644 --- a/packages/mcp-server/src/tools/pdf-operations/split-pdf-operations.ts +++ b/packages/mcp-server/src/tools/pdf-operations/split-pdf-operations.ts @@ -16,8 +16,7 @@ export const metadata: Metadata = { export const tool: Tool = { name: 'split_pdf_operations', - description: - "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nCreates a task to split a PDF file into multiple single-page PDF files.", + description: 'Creates a task to split a PDF file into multiple single-page PDF files.', inputSchema: { type: 'object', properties: { diff --git a/packages/mcp-server/src/tools/tasks/list-tasks.ts b/packages/mcp-server/src/tools/tasks/list-tasks.ts index f8c3702..62db276 100644 --- a/packages/mcp-server/src/tools/tasks/list-tasks.ts +++ b/packages/mcp-server/src/tools/tasks/list-tasks.ts @@ -16,8 +16,7 @@ export const metadata: Metadata = { export const tool: Tool = { name: 'list_tasks', - description: - "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nRetrieves a paginated list of tasks belonging to the authenticated user.", + description: 'Retrieves a paginated list of tasks belonging to the authenticated user.', inputSchema: { type: 'object', properties: { diff --git a/packages/mcp-server/src/tools/tasks/retrieve-tasks.ts b/packages/mcp-server/src/tools/tasks/retrieve-tasks.ts index 8ea1147..5c1e48c 100644 --- a/packages/mcp-server/src/tools/tasks/retrieve-tasks.ts +++ b/packages/mcp-server/src/tools/tasks/retrieve-tasks.ts @@ -16,8 +16,7 @@ export const metadata: Metadata = { export const tool: Tool = { name: 'retrieve_tasks', - description: - "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nRetrieves the data for a specific task by its ID.", + description: 'Retrieves the data for a specific task by its ID.', inputSchema: { type: 'object', properties: { From 41bd333e563e4b23100f1f239928aa8c60fc223c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 1 Aug 2025 04:40:02 +0000 Subject: [PATCH 62/91] fix(mcp): reverse validJson capability option and limit scope --- packages/mcp-server/src/compat.ts | 7 +- packages/mcp-server/src/server.ts | 2 +- packages/mcp-server/tests/options.test.ts | 133 ++++++++++++++++++++++ 3 files changed, 139 insertions(+), 3 deletions(-) diff --git a/packages/mcp-server/src/compat.ts b/packages/mcp-server/src/compat.ts index ff0d6d4..7afd77f 100644 --- a/packages/mcp-server/src/compat.ts +++ b/packages/mcp-server/src/compat.ts @@ -70,8 +70,11 @@ export function parseEmbeddedJSON(args: Record, schema: Record< if (typeof value === 'string') { try { const parsed = JSON.parse(value); - newArgs[key] = parsed; - updated = true; + // Only parse if result is a plain object (not array, null, or primitive) + if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) { + newArgs[key] = parsed; + updated = true; + } } catch (e) { // Not valid JSON, leave as is } diff --git a/packages/mcp-server/src/server.ts b/packages/mcp-server/src/server.ts index 6003f4a..92ed44a 100644 --- a/packages/mcp-server/src/server.ts +++ b/packages/mcp-server/src/server.ts @@ -117,7 +117,7 @@ export async function executeHandler( compatibilityOptions?: Partial, ) { const options = { ...defaultClientCapabilities, ...compatibilityOptions }; - if (options.validJson && args) { + if (!options.validJson && args) { args = parseEmbeddedJSON(args, tool.inputSchema); } return await handler(client, args || {}); diff --git a/packages/mcp-server/tests/options.test.ts b/packages/mcp-server/tests/options.test.ts index f7661d6..264aca5 100644 --- a/packages/mcp-server/tests/options.test.ts +++ b/packages/mcp-server/tests/options.test.ts @@ -1,5 +1,6 @@ import { parseOptions } from '../src/options'; import { Filter } from '../src/tools'; +import { parseEmbeddedJSON } from '../src/compat'; // Mock process.argv const mockArgv = (args: string[]) => { @@ -184,3 +185,135 @@ describe('parseOptions', () => { cleanup(); }); }); + +describe('parseEmbeddedJSON', () => { + it('should not change non-string values', () => { + const args = { + numberProp: 42, + booleanProp: true, + objectProp: { nested: 'value' }, + arrayProp: [1, 2, 3], + nullProp: null, + undefinedProp: undefined, + }; + const schema = {}; + + const result = parseEmbeddedJSON(args, schema); + + expect(result).toBe(args); // Should return original object since no changes made + expect(result['numberProp']).toBe(42); + expect(result['booleanProp']).toBe(true); + expect(result['objectProp']).toEqual({ nested: 'value' }); + expect(result['arrayProp']).toEqual([1, 2, 3]); + expect(result['nullProp']).toBe(null); + expect(result['undefinedProp']).toBe(undefined); + }); + + it('should parse valid JSON objects in string properties', () => { + const args = { + jsonObjectString: '{"key": "value", "number": 123}', + regularString: 'not json', + }; + const schema = {}; + + const result = parseEmbeddedJSON(args, schema); + + expect(result).not.toBe(args); // Should return new object since changes were made + expect(result['jsonObjectString']).toEqual({ key: 'value', number: 123 }); + expect(result['regularString']).toBe('not json'); + }); + + it('should leave invalid JSON in string properties unchanged', () => { + const args = { + invalidJson1: '{"key": value}', // Missing quotes around value + invalidJson2: '{key: "value"}', // Missing quotes around key + invalidJson3: '{"key": "value",}', // Trailing comma + invalidJson4: 'just a regular string', + emptyString: '', + }; + const schema = {}; + + const result = parseEmbeddedJSON(args, schema); + + expect(result).toBe(args); // Should return original object since no changes made + expect(result['invalidJson1']).toBe('{"key": value}'); + expect(result['invalidJson2']).toBe('{key: "value"}'); + expect(result['invalidJson3']).toBe('{"key": "value",}'); + expect(result['invalidJson4']).toBe('just a regular string'); + expect(result['emptyString']).toBe(''); + }); + + it('should not parse JSON primitives in string properties', () => { + const args = { + numberString: '123', + floatString: '45.67', + negativeNumberString: '-89', + booleanTrueString: 'true', + booleanFalseString: 'false', + nullString: 'null', + jsonArrayString: '[1, 2, 3, "test"]', + regularString: 'not json', + }; + const schema = {}; + + const result = parseEmbeddedJSON(args, schema); + + expect(result).toBe(args); // Should return original object since no changes made + expect(result['numberString']).toBe('123'); + expect(result['floatString']).toBe('45.67'); + expect(result['negativeNumberString']).toBe('-89'); + expect(result['booleanTrueString']).toBe('true'); + expect(result['booleanFalseString']).toBe('false'); + expect(result['nullString']).toBe('null'); + expect(result['jsonArrayString']).toBe('[1, 2, 3, "test"]'); + expect(result['regularString']).toBe('not json'); + }); + + it('should handle mixed valid objects and other JSON types', () => { + const args = { + validObject: '{"success": true}', + invalidObject: '{"missing": quote}', + validNumber: '42', + validArray: '[1, 2, 3]', + keepAsString: 'hello world', + nonString: 123, + }; + const schema = {}; + + const result = parseEmbeddedJSON(args, schema); + + expect(result).not.toBe(args); // Should return new object since some changes were made + expect(result['validObject']).toEqual({ success: true }); + expect(result['invalidObject']).toBe('{"missing": quote}'); + expect(result['validNumber']).toBe('42'); // Not parsed, remains string + expect(result['validArray']).toBe('[1, 2, 3]'); // Not parsed, remains string + expect(result['keepAsString']).toBe('hello world'); + expect(result['nonString']).toBe(123); + }); + + it('should return original object when no strings are present', () => { + const args = { + number: 42, + boolean: true, + object: { key: 'value' }, + }; + const schema = {}; + + const result = parseEmbeddedJSON(args, schema); + + expect(result).toBe(args); // Should return original object since no changes made + }); + + it('should return original object when all strings are invalid JSON', () => { + const args = { + string1: 'hello', + string2: 'world', + string3: 'not json at all', + }; + const schema = {}; + + const result = parseEmbeddedJSON(args, schema); + + expect(result).toBe(args); // Should return original object since no changes made + }); +}); From 11b40cca569792c127c204a6ca9c39e688b182be Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 1 Aug 2025 04:41:54 +0000 Subject: [PATCH 63/91] fix(mcp): avoid sending `jq_filter` to base API --- packages/mcp-server/src/tools/files/delete-files.ts | 9 +-------- packages/mcp-server/src/tools/files/download-files.ts | 9 +-------- packages/mcp-server/src/tools/files/list-files.ts | 4 ++-- packages/mcp-server/src/tools/files/retrieve-files.ts | 4 ++-- packages/mcp-server/src/tools/files/upload-files.ts | 4 ++-- 5 files changed, 8 insertions(+), 22 deletions(-) diff --git a/packages/mcp-server/src/tools/files/delete-files.ts b/packages/mcp-server/src/tools/files/delete-files.ts index b080708..a2a81c5 100644 --- a/packages/mcp-server/src/tools/files/delete-files.ts +++ b/packages/mcp-server/src/tools/files/delete-files.ts @@ -16,20 +16,13 @@ export const metadata: Metadata = { export const tool: Tool = { name: 'delete_files', - description: - "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nDeletes a specific file by its ID.\n\n# Response Schema\n```json\n{\n type: 'object',\n properties: {}\n}\n```", + description: 'Deletes a specific file by its ID.', inputSchema: { type: 'object', properties: { id: { type: 'string', }, - jq_filter: { - type: 'string', - title: 'jq Filter', - description: - 'A jq filter to apply to the response to include certain fields. Consult the output schema in the tool description to see the fields that are available.\n\nFor example: to include only the `name` field in every object of a results array, you can provide ".results[].name".\n\nFor more information, see the [jq documentation](https://jqlang.org/manual/).', - }, }, required: ['id'], }, diff --git a/packages/mcp-server/src/tools/files/download-files.ts b/packages/mcp-server/src/tools/files/download-files.ts index 5c3951f..36790ce 100644 --- a/packages/mcp-server/src/tools/files/download-files.ts +++ b/packages/mcp-server/src/tools/files/download-files.ts @@ -16,20 +16,13 @@ export const metadata: Metadata = { export const tool: Tool = { name: 'download_files', - description: - "When using this tool, always use the `jq_filter` parameter to reduce the response size and improve performance.\n\nOnly omit if you're sure you don't need the data.\n\nDownloads the content of a specific file by its ID.\n\n# Response Schema\n```json\n{\n type: 'string'\n}\n```", + description: 'Downloads the content of a specific file by its ID.', inputSchema: { type: 'object', properties: { id: { type: 'string', }, - jq_filter: { - type: 'string', - title: 'jq Filter', - description: - 'A jq filter to apply to the response to include certain fields. Consult the output schema in the tool description to see the fields that are available.\n\nFor example: to include only the `name` field in every object of a results array, you can provide ".results[].name".\n\nFor more information, see the [jq documentation](https://jqlang.org/manual/).', - }, }, required: ['id'], }, diff --git a/packages/mcp-server/src/tools/files/list-files.ts b/packages/mcp-server/src/tools/files/list-files.ts index 8d80803..9331697 100644 --- a/packages/mcp-server/src/tools/files/list-files.ts +++ b/packages/mcp-server/src/tools/files/list-files.ts @@ -45,8 +45,8 @@ export const tool: Tool = { }; export const handler = async (client: ScanDocuments, args: Record | undefined) => { - const body = args as any; - return asTextContentResult(await maybeFilter(args, await client.files.list(body))); + const { jq_filter, ...body } = args as any; + return asTextContentResult(await maybeFilter(jq_filter, await client.files.list(body))); }; export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/files/retrieve-files.ts b/packages/mcp-server/src/tools/files/retrieve-files.ts index 10223c9..131e114 100644 --- a/packages/mcp-server/src/tools/files/retrieve-files.ts +++ b/packages/mcp-server/src/tools/files/retrieve-files.ts @@ -40,8 +40,8 @@ export const tool: Tool = { }; export const handler = async (client: ScanDocuments, args: Record | undefined) => { - const { id, ...body } = args as any; - return asTextContentResult(await maybeFilter(args, await client.files.retrieve(id))); + const { id, jq_filter, ...body } = args as any; + return asTextContentResult(await maybeFilter(jq_filter, await client.files.retrieve(id))); }; export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/files/upload-files.ts b/packages/mcp-server/src/tools/files/upload-files.ts index 5bb64e2..772e51c 100644 --- a/packages/mcp-server/src/tools/files/upload-files.ts +++ b/packages/mcp-server/src/tools/files/upload-files.ts @@ -43,8 +43,8 @@ export const tool: Tool = { }; export const handler = async (client: ScanDocuments, args: Record | undefined) => { - const body = args as any; - return asTextContentResult(await maybeFilter(args, await client.files.upload(body))); + const { jq_filter, ...body } = args as any; + return asTextContentResult(await maybeFilter(jq_filter, await client.files.upload(body))); }; export default { metadata, tool, handler }; From 57fc7959d83c30d25152a60aeb8895df38ab15b8 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 2 Aug 2025 05:31:34 +0000 Subject: [PATCH 64/91] feat(mcp): add logging when environment variable is set --- packages/mcp-server/src/server.ts | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/packages/mcp-server/src/server.ts b/packages/mcp-server/src/server.ts index 92ed44a..5240f89 100644 --- a/packages/mcp-server/src/server.ts +++ b/packages/mcp-server/src/server.ts @@ -28,7 +28,7 @@ export const server = new McpServer( name: 'scan_documents_api', version: '0.1.0-alpha.5', }, - { capabilities: { tools: {} } }, + { capabilities: { tools: {}, logging: {} } }, ); /** @@ -61,7 +61,24 @@ export function init(params: { const endpointMap = Object.fromEntries(providedEndpoints.map((endpoint) => [endpoint.tool.name, endpoint])); - const client = params.client || new ScanDocuments({ defaultHeaders: { 'X-Stainless-MCP': 'true' } }); + const logAtLevel = + (level: 'debug' | 'info' | 'warning' | 'error') => + (message: string, ...rest: unknown[]) => { + console.error(message, ...rest); + void server.sendLoggingMessage({ + level, + data: { message, rest }, + }); + }; + const logger = { + debug: logAtLevel('debug'), + info: logAtLevel('info'), + warn: logAtLevel('warning'), + error: logAtLevel('error'), + }; + + const client = + params.client || new ScanDocuments({ defaultHeaders: { 'X-Stainless-MCP': 'true' }, logger: logger }); server.setRequestHandler(ListToolsRequestSchema, async () => { return { From 05f1022cf2d8897c5ca52bdac865fea951dabc39 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 5 Aug 2025 07:00:23 +0000 Subject: [PATCH 65/91] feat(mcp): remote server with passthru auth --- packages/mcp-server/package.json | 2 + packages/mcp-server/src/headers.ts | 11 ++++ packages/mcp-server/src/http.ts | 85 ++++++++++++++++++++++++++++++ packages/mcp-server/src/index.ts | 26 +++++---- packages/mcp-server/src/options.ts | 16 ++++++ packages/mcp-server/src/server.ts | 19 ++++--- packages/mcp-server/src/stdio.ts | 14 +++++ 7 files changed, 154 insertions(+), 19 deletions(-) create mode 100644 packages/mcp-server/src/headers.ts create mode 100644 packages/mcp-server/src/http.ts create mode 100644 packages/mcp-server/src/stdio.ts diff --git a/packages/mcp-server/package.json b/packages/mcp-server/package.json index 7a96a7b..b198e5c 100644 --- a/packages/mcp-server/package.json +++ b/packages/mcp-server/package.json @@ -29,6 +29,7 @@ "dependencies": { "scan-documents": "file:../../dist/", "@modelcontextprotocol/sdk": "^1.11.5", + "express": "^5.1.0", "jq-web": "https://github.com/stainless-api/jq-web/releases/download/v0.8.2/jq-web.tar.gz", "yargs": "^17.7.2", "@cloudflare/cabidela": "^0.2.4", @@ -40,6 +41,7 @@ }, "devDependencies": { "@types/jest": "^29.4.0", + "@types/express": "^5.0.3", "@typescript-eslint/eslint-plugin": "8.31.1", "@typescript-eslint/parser": "8.31.1", "eslint": "^8.49.0", diff --git a/packages/mcp-server/src/headers.ts b/packages/mcp-server/src/headers.ts new file mode 100644 index 0000000..17994ea --- /dev/null +++ b/packages/mcp-server/src/headers.ts @@ -0,0 +1,11 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { type ClientOptions } from 'scan-documents/client'; + +import { IncomingMessage } from 'node:http'; + +export const parseAuthHeaders = (req: IncomingMessage): Partial => { + const apiKey = + req.headers['x-api-key'] instanceof Array ? req.headers['x-api-key'][0] : req.headers['x-api-key']; + return { apiKey }; +}; diff --git a/packages/mcp-server/src/http.ts b/packages/mcp-server/src/http.ts new file mode 100644 index 0000000..be3864c --- /dev/null +++ b/packages/mcp-server/src/http.ts @@ -0,0 +1,85 @@ +import { McpServer } from '@modelcontextprotocol/sdk/server/mcp'; +import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js'; + +import express from 'express'; +import { McpOptions } from './options'; +import { initMcpServer, newMcpServer } from './server'; +import { parseAuthHeaders } from './headers'; +import { Endpoint } from './tools'; + +const newServer = (mcpOptions: McpOptions, req: express.Request, res: express.Response): McpServer | null => { + const server = newMcpServer(); + try { + const authOptions = parseAuthHeaders(req); + initMcpServer({ + server: server, + clientOptions: { + ...authOptions, + defaultHeaders: { + 'X-Stainless-MCP': 'true', + }, + }, + mcpOptions, + }); + } catch { + res.status(401).json({ + jsonrpc: '2.0', + error: { + code: -32000, + message: 'Unauthorized', + }, + }); + return null; + } + + return server; +}; + +const post = (defaultOptions: McpOptions) => async (req: express.Request, res: express.Response) => { + const server = newServer(defaultOptions, req, res); + // If we return null, we already set the authorization error. + if (server === null) return; + const transport = new StreamableHTTPServerTransport({ + // Stateless server + sessionIdGenerator: undefined, + }); + await server.connect(transport); + await transport.handleRequest(req, res, req.body); +}; + +const get = async (req: express.Request, res: express.Response) => { + res.status(405).json({ + jsonrpc: '2.0', + error: { + code: -32000, + message: 'Method not supported', + }, + }); +}; + +const del = async (req: express.Request, res: express.Response) => { + res.status(405).json({ + jsonrpc: '2.0', + error: { + code: -32000, + message: 'Method not supported', + }, + }); +}; + +export const launchStreamableHTTPServer = async ( + options: McpOptions, + endpoints: Endpoint[], + port: number | undefined, +) => { + const app = express(); + app.use(express.json()); + + app.get('/', get); + app.post('/', post(options)); + app.delete('/', del); + + console.error(`MCP Server running on streamable HTTP on port ${port}`); + + app.listen(port); +}; diff --git a/packages/mcp-server/src/index.ts b/packages/mcp-server/src/index.ts index 0621357..7a4f138 100644 --- a/packages/mcp-server/src/index.ts +++ b/packages/mcp-server/src/index.ts @@ -1,9 +1,10 @@ #!/usr/bin/env node -import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; -import { init, selectTools, server } from './server'; +import { selectTools } from './server'; import { Endpoint, endpoints } from './tools'; import { McpOptions, parseOptions } from './options'; +import { launchStdioServer } from './stdio'; +import { launchStreamableHTTPServer } from './http'; async function main() { const options = parseOptionsOrError(); @@ -13,18 +14,21 @@ async function main() { return; } - const includedTools = selectToolsOrError(endpoints, options); + const selectedTools = selectToolsOrError(endpoints, options); console.error( - `MCP Server starting with ${includedTools.length} tools:`, - includedTools.map((e) => e.tool.name), + `MCP Server starting with ${selectedTools.length} tools:`, + selectedTools.map((e) => e.tool.name), ); - init({ server, endpoints: includedTools }); - - const transport = new StdioServerTransport(); - await server.connect(transport); - console.error('MCP Server running on stdio'); + switch (options.transport) { + case 'stdio': + await launchStdioServer(options, selectedTools); + break; + case 'http': + await launchStreamableHTTPServer(options, selectedTools, options.port); + break; + } } if (require.main === module) { @@ -43,7 +47,7 @@ function parseOptionsOrError() { } } -function selectToolsOrError(endpoints: Endpoint[], options: McpOptions) { +function selectToolsOrError(endpoints: Endpoint[], options: McpOptions): Endpoint[] { try { const includedTools = selectTools(endpoints, options); if (includedTools.length === 0) { diff --git a/packages/mcp-server/src/options.ts b/packages/mcp-server/src/options.ts index c075101..daf5838 100644 --- a/packages/mcp-server/src/options.ts +++ b/packages/mcp-server/src/options.ts @@ -5,6 +5,8 @@ import { ClientCapabilities, knownClients, ClientType } from './compat'; export type CLIOptions = McpOptions & { list: boolean; + transport: 'stdio' | 'http'; + port: number | undefined; }; export type McpOptions = { @@ -129,6 +131,16 @@ export function parseOptions(): CLIOptions { type: 'boolean', description: 'Print detailed explanation of client capabilities and exit', }) + .option('transport', { + type: 'string', + choices: ['stdio', 'http'], + default: 'stdio', + description: 'What transport to use; stdio for local servers or http for remote servers', + }) + .option('port', { + type: 'number', + description: 'Port to serve on if using http transport', + }) .help(); for (const [command, desc] of examples()) { @@ -238,6 +250,8 @@ export function parseOptions(): CLIOptions { const includeAllTools = explicitTools ? argv.tools?.includes('all') && !argv.noTools?.includes('all') : undefined; + const transport = argv.transport as 'stdio' | 'http'; + const client = argv.client as ClientType; return { client: client && knownClients[client] ? client : undefined, @@ -246,6 +260,8 @@ export function parseOptions(): CLIOptions { filters, capabilities: clientCapabilities, list: argv.list || false, + transport, + port: argv.port, }; } diff --git a/packages/mcp-server/src/server.ts b/packages/mcp-server/src/server.ts index 5240f89..a8e3edf 100644 --- a/packages/mcp-server/src/server.ts +++ b/packages/mcp-server/src/server.ts @@ -22,14 +22,17 @@ export { Filter } from './tools'; export { ClientOptions } from 'scan-documents'; export { endpoints } from './tools'; +export const newMcpServer = () => + new McpServer( + { + name: 'scan_documents_api', + version: '0.1.0-alpha.5', + }, + { capabilities: { tools: {}, logging: {} } }, + ); + // Create server instance -export const server = new McpServer( - { - name: 'scan_documents_api', - version: '0.1.0-alpha.5', - }, - { capabilities: { tools: {}, logging: {} } }, -); +export const server = newMcpServer(); /** * Initializes the provided MCP Server with the given tools and handlers. @@ -100,7 +103,7 @@ export function init(params: { /** * Selects the tools to include in the MCP Server based on the provided options. */ -export function selectTools(endpoints: Endpoint[], options: McpOptions) { +export function selectTools(endpoints: Endpoint[], options: McpOptions): Endpoint[] { const filteredEndpoints = query(options.filters, endpoints); let includedTools = filteredEndpoints; diff --git a/packages/mcp-server/src/stdio.ts b/packages/mcp-server/src/stdio.ts new file mode 100644 index 0000000..b269163 --- /dev/null +++ b/packages/mcp-server/src/stdio.ts @@ -0,0 +1,14 @@ +import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; +import { init, newMcpServer } from './server'; +import { Endpoint } from './tools'; +import { McpOptions } from './options'; + +export const launchStdioServer = async (options: McpOptions, endpoints: Endpoint[]) => { + const server = newMcpServer(); + + init({ server, endpoints }); + + const transport = new StdioServerTransport(); + await server.connect(transport); + console.error('MCP Server running on stdio'); +}; From 1947212b285dd090527c98fb607308003036e1e3 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 7 Aug 2025 04:07:48 +0000 Subject: [PATCH 66/91] chore(internal): move publish config --- bin/publish-npm | 2 +- package.json | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/bin/publish-npm b/bin/publish-npm index fa2243d..45e8aa8 100644 --- a/bin/publish-npm +++ b/bin/publish-npm @@ -58,4 +58,4 @@ else fi # Publish with the appropriate tag -yarn publish --access public --tag "$TAG" +yarn publish --tag "$TAG" diff --git a/package.json b/package.json index d87bc9e..a1efe2d 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,9 @@ "**/*" ], "private": false, + "publishConfig": { + "access": "public" + }, "scripts": { "test": "./scripts/test", "build": "./scripts/build", From 8a955eaa7bb01a0a85817567cd0000a15cdca487 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 7 Aug 2025 04:10:37 +0000 Subject: [PATCH 67/91] chore(mcp): refactor streamable http transport --- packages/mcp-server/src/http.ts | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/packages/mcp-server/src/http.ts b/packages/mcp-server/src/http.ts index be3864c..d64f723 100644 --- a/packages/mcp-server/src/http.ts +++ b/packages/mcp-server/src/http.ts @@ -1,3 +1,5 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + import { McpServer } from '@modelcontextprotocol/sdk/server/mcp'; import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js'; @@ -67,11 +69,7 @@ const del = async (req: express.Request, res: express.Response) => { }); }; -export const launchStreamableHTTPServer = async ( - options: McpOptions, - endpoints: Endpoint[], - port: number | undefined, -) => { +export const streamableHTTPApp = (options: McpOptions) => { const app = express(); app.use(express.json()); @@ -79,7 +77,23 @@ export const launchStreamableHTTPServer = async ( app.post('/', post(options)); app.delete('/', del); - console.error(`MCP Server running on streamable HTTP on port ${port}`); + return app; +}; + +export const launchStreamableHTTPServer = async ( + options: McpOptions, + endpoints: Endpoint[], + port: number | undefined, +) => { + const app = streamableHTTPApp(options); + const server = app.listen(port); + const address = server.address(); - app.listen(port); + if (typeof address === 'string') { + console.error(`MCP Server running on streamable HTTP at ${address}`); + } else if (address !== null) { + console.error(`MCP Server running on streamable HTTP on port ${address.port}`); + } else { + console.error(`MCP Server running on streamable HTTP on port ${port}`); + } }; From 72982bc112a6a5725956354b361944069cf92faa Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 7 Aug 2025 04:11:25 +0000 Subject: [PATCH 68/91] feat(mcp): add unix socket option for remote MCP --- packages/mcp-server/src/http.ts | 2 +- packages/mcp-server/src/index.ts | 2 +- packages/mcp-server/src/options.ts | 6 ++++++ packages/mcp-server/src/server.ts | 1 - 4 files changed, 8 insertions(+), 3 deletions(-) diff --git a/packages/mcp-server/src/http.ts b/packages/mcp-server/src/http.ts index d64f723..900e131 100644 --- a/packages/mcp-server/src/http.ts +++ b/packages/mcp-server/src/http.ts @@ -83,7 +83,7 @@ export const streamableHTTPApp = (options: McpOptions) => { export const launchStreamableHTTPServer = async ( options: McpOptions, endpoints: Endpoint[], - port: number | undefined, + port: number | string | undefined, ) => { const app = streamableHTTPApp(options); const server = app.listen(port); diff --git a/packages/mcp-server/src/index.ts b/packages/mcp-server/src/index.ts index 7a4f138..4c71a3b 100644 --- a/packages/mcp-server/src/index.ts +++ b/packages/mcp-server/src/index.ts @@ -26,7 +26,7 @@ async function main() { await launchStdioServer(options, selectedTools); break; case 'http': - await launchStreamableHTTPServer(options, selectedTools, options.port); + await launchStreamableHTTPServer(options, selectedTools, options.port ?? options.socket); break; } } diff --git a/packages/mcp-server/src/options.ts b/packages/mcp-server/src/options.ts index daf5838..c290ca5 100644 --- a/packages/mcp-server/src/options.ts +++ b/packages/mcp-server/src/options.ts @@ -7,6 +7,7 @@ export type CLIOptions = McpOptions & { list: boolean; transport: 'stdio' | 'http'; port: number | undefined; + socket: string | undefined; }; export type McpOptions = { @@ -141,6 +142,10 @@ export function parseOptions(): CLIOptions { type: 'number', description: 'Port to serve on if using http transport', }) + .option('socket', { + type: 'string', + description: 'Unix socket to serve on if using http transport', + }) .help(); for (const [command, desc] of examples()) { @@ -262,6 +267,7 @@ export function parseOptions(): CLIOptions { list: argv.list || false, transport, port: argv.port, + socket: argv.socket, }; } diff --git a/packages/mcp-server/src/server.ts b/packages/mcp-server/src/server.ts index a8e3edf..7b7c0d9 100644 --- a/packages/mcp-server/src/server.ts +++ b/packages/mcp-server/src/server.ts @@ -67,7 +67,6 @@ export function init(params: { const logAtLevel = (level: 'debug' | 'info' | 'warning' | 'error') => (message: string, ...rest: unknown[]) => { - console.error(message, ...rest); void server.sendLoggingMessage({ level, data: { message, rest }, From b609b338d3f8db485a3ede5f4fe920db21c79149 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 9 Aug 2025 04:55:02 +0000 Subject: [PATCH 69/91] chore: update @stainless-api/prism-cli to v5.15.0 --- scripts/mock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/mock b/scripts/mock index d2814ae..0b28f6e 100755 --- a/scripts/mock +++ b/scripts/mock @@ -21,7 +21,7 @@ echo "==> Starting mock server with URL ${URL}" # Run prism mock on the given spec if [ "$1" == "--daemon" ]; then - npm exec --package=@stainless-api/prism-cli@5.8.5 -- prism mock "$URL" &> .prism.log & + npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock "$URL" &> .prism.log & # Wait for server to come online echo -n "Waiting for server" @@ -37,5 +37,5 @@ if [ "$1" == "--daemon" ]; then echo else - npm exec --package=@stainless-api/prism-cli@5.8.5 -- prism mock "$URL" + npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock "$URL" fi From 3be780cb1d9bc7136a79a2f130617a42bd38b081 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 9 Aug 2025 04:57:47 +0000 Subject: [PATCH 70/91] chore(internal): update comment in script --- scripts/test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/test b/scripts/test index 2049e31..7bce051 100755 --- a/scripts/test +++ b/scripts/test @@ -43,7 +43,7 @@ elif ! prism_is_running ; then echo -e "To run the server, pass in the path or url of your OpenAPI" echo -e "spec to the prism command:" echo - echo -e " \$ ${YELLOW}npm exec --package=@stoplight/prism-cli@~5.3.2 -- prism mock path/to/your.openapi.yml${NC}" + echo -e " \$ ${YELLOW}npm exec --package=@stainless-api/prism-cli@5.15.0 -- prism mock path/to/your.openapi.yml${NC}" echo exit 1 From 4d9ab3563cfe93b7a61097a484e9f37f7604c5b7 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 12 Aug 2025 02:33:02 +0000 Subject: [PATCH 71/91] chore(internal): codegen related update --- packages/mcp-server/package.json | 2 +- packages/mcp-server/src/filtering.ts | 3 +-- tests/api-resources/events.test.ts | 4 ++-- tests/api-resources/files.test.ts | 12 +++++----- tests/api-resources/image-operations.test.ts | 24 ++++++++++---------- tests/api-resources/pdf-operations.test.ts | 16 ++++++------- tests/api-resources/tasks.test.ts | 6 ++--- 7 files changed, 33 insertions(+), 34 deletions(-) diff --git a/packages/mcp-server/package.json b/packages/mcp-server/package.json index b198e5c..ae0f2ed 100644 --- a/packages/mcp-server/package.json +++ b/packages/mcp-server/package.json @@ -30,7 +30,7 @@ "scan-documents": "file:../../dist/", "@modelcontextprotocol/sdk": "^1.11.5", "express": "^5.1.0", - "jq-web": "https://github.com/stainless-api/jq-web/releases/download/v0.8.2/jq-web.tar.gz", + "jq-web": "https://github.com/stainless-api/jq-web/releases/download/v0.8.6/jq-web.tar.gz", "yargs": "^17.7.2", "@cloudflare/cabidela": "^0.2.4", "zod": "^3.25.20", diff --git a/packages/mcp-server/src/filtering.ts b/packages/mcp-server/src/filtering.ts index 87eab2d..1aa9a40 100644 --- a/packages/mcp-server/src/filtering.ts +++ b/packages/mcp-server/src/filtering.ts @@ -1,8 +1,7 @@ // @ts-nocheck import initJq from 'jq-web'; -export async function maybeFilter(args: Record | undefined, response: any): Promise { - const jqFilter = args?.['jq_filter']; +export async function maybeFilter(jqFilter: unknown | undefined, response: any): Promise { if (jqFilter && typeof jqFilter === 'string') { return await jq(response, jqFilter); } else { diff --git a/tests/api-resources/events.test.ts b/tests/api-resources/events.test.ts index dc19fa5..b795fb3 100644 --- a/tests/api-resources/events.test.ts +++ b/tests/api-resources/events.test.ts @@ -8,7 +8,7 @@ const client = new ScanDocuments({ }); describe('resource events', () => { - // skipped: tests are disabled for the time being + // Prism tests are disabled test.skip('list', async () => { const responsePromise = client.events.list(); const rawResponse = await responsePromise.asResponse(); @@ -20,7 +20,7 @@ describe('resource events', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - // skipped: tests are disabled for the time being + // Prism tests are disabled test.skip('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/files.test.ts b/tests/api-resources/files.test.ts index 2526df0..eab9ce8 100644 --- a/tests/api-resources/files.test.ts +++ b/tests/api-resources/files.test.ts @@ -8,7 +8,7 @@ const client = new ScanDocuments({ }); describe('resource files', () => { - // skipped: tests are disabled for the time being + // Prism tests are disabled test.skip('retrieve', async () => { const responsePromise = client.files.retrieve('id'); const rawResponse = await responsePromise.asResponse(); @@ -20,7 +20,7 @@ describe('resource files', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - // skipped: tests are disabled for the time being + // Prism tests are disabled test.skip('list', async () => { const responsePromise = client.files.list(); const rawResponse = await responsePromise.asResponse(); @@ -32,7 +32,7 @@ describe('resource files', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - // skipped: tests are disabled for the time being + // Prism tests are disabled test.skip('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( @@ -40,7 +40,7 @@ describe('resource files', () => { ).rejects.toThrow(ScanDocuments.NotFoundError); }); - // skipped: tests are disabled for the time being + // Prism tests are disabled test.skip('delete', async () => { const responsePromise = client.files.delete('id'); const rawResponse = await responsePromise.asResponse(); @@ -52,7 +52,7 @@ describe('resource files', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - // skipped: tests are disabled for the time being + // Prism tests are disabled test.skip('upload: only required params', async () => { const responsePromise = client.files.upload({ file: await toFile(Buffer.from('# my file contents'), 'README.md'), @@ -67,7 +67,7 @@ describe('resource files', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - // skipped: tests are disabled for the time being + // Prism tests are disabled test.skip('upload: required and optional params', async () => { const response = await client.files.upload({ file: await toFile(Buffer.from('# my file contents'), 'README.md'), diff --git a/tests/api-resources/image-operations.test.ts b/tests/api-resources/image-operations.test.ts index b0fafc0..2036b06 100644 --- a/tests/api-resources/image-operations.test.ts +++ b/tests/api-resources/image-operations.test.ts @@ -8,7 +8,7 @@ const client = new ScanDocuments({ }); describe('resource imageOperations', () => { - // skipped: tests are disabled for the time being + // Prism tests are disabled test.skip('applyEffect: only required params', async () => { const responsePromise = client.imageOperations.applyEffect({ effect: 'grayscale', @@ -23,7 +23,7 @@ describe('resource imageOperations', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - // skipped: tests are disabled for the time being + // Prism tests are disabled test.skip('applyEffect: required and optional params', async () => { const response = await client.imageOperations.applyEffect({ effect: 'grayscale', @@ -33,7 +33,7 @@ describe('resource imageOperations', () => { }); }); - // skipped: tests are disabled for the time being + // Prism tests are disabled test.skip('convert: only required params', async () => { const responsePromise = client.imageOperations.convert({ input: 'file_avyrvozb9302uwhq', @@ -48,7 +48,7 @@ describe('resource imageOperations', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - // skipped: tests are disabled for the time being + // Prism tests are disabled test.skip('convert: required and optional params', async () => { const response = await client.imageOperations.convert({ input: 'file_avyrvozb9302uwhq', @@ -58,7 +58,7 @@ describe('resource imageOperations', () => { }); }); - // skipped: tests are disabled for the time being + // Prism tests are disabled test.skip('detectDocuments: only required params', async () => { const responsePromise = client.imageOperations.detectDocuments({ input: 'file_avyrvozb9302uwhq' }); const rawResponse = await responsePromise.asResponse(); @@ -70,7 +70,7 @@ describe('resource imageOperations', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - // skipped: tests are disabled for the time being + // Prism tests are disabled test.skip('detectDocuments: required and optional params', async () => { const response = await client.imageOperations.detectDocuments({ input: 'file_avyrvozb9302uwhq', @@ -78,7 +78,7 @@ describe('resource imageOperations', () => { }); }); - // skipped: tests are disabled for the time being + // Prism tests are disabled test.skip('extractText: only required params', async () => { const responsePromise = client.imageOperations.extractText({ format: 'plain', @@ -93,7 +93,7 @@ describe('resource imageOperations', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - // skipped: tests are disabled for the time being + // Prism tests are disabled test.skip('extractText: required and optional params', async () => { const response = await client.imageOperations.extractText({ format: 'plain', @@ -102,7 +102,7 @@ describe('resource imageOperations', () => { }); }); - // skipped: tests are disabled for the time being + // Prism tests are disabled test.skip('scan: only required params', async () => { const responsePromise = client.imageOperations.scan({ effect: 'none', @@ -118,7 +118,7 @@ describe('resource imageOperations', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - // skipped: tests are disabled for the time being + // Prism tests are disabled test.skip('scan: required and optional params', async () => { const response = await client.imageOperations.scan({ effect: 'none', @@ -129,7 +129,7 @@ describe('resource imageOperations', () => { }); }); - // skipped: tests are disabled for the time being + // Prism tests are disabled test.skip('warp: only required params', async () => { const responsePromise = client.imageOperations.warp({ input: 'file_avyrvozb9302uwhq', @@ -149,7 +149,7 @@ describe('resource imageOperations', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - // skipped: tests are disabled for the time being + // Prism tests are disabled test.skip('warp: required and optional params', async () => { const response = await client.imageOperations.warp({ input: 'file_avyrvozb9302uwhq', diff --git a/tests/api-resources/pdf-operations.test.ts b/tests/api-resources/pdf-operations.test.ts index dc39d81..42a9f2f 100644 --- a/tests/api-resources/pdf-operations.test.ts +++ b/tests/api-resources/pdf-operations.test.ts @@ -8,7 +8,7 @@ const client = new ScanDocuments({ }); describe('resource pdfOperations', () => { - // skipped: tests are disabled for the time being + // Prism tests are disabled test.skip('extractPages: only required params', async () => { const responsePromise = client.pdfOperations.extractPages({ input: 'file_avyrvozb9302uwhq', @@ -23,7 +23,7 @@ describe('resource pdfOperations', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - // skipped: tests are disabled for the time being + // Prism tests are disabled test.skip('extractPages: required and optional params', async () => { const response = await client.pdfOperations.extractPages({ input: 'file_avyrvozb9302uwhq', @@ -33,7 +33,7 @@ describe('resource pdfOperations', () => { }); }); - // skipped: tests are disabled for the time being + // Prism tests are disabled test.skip('merge: only required params', async () => { const responsePromise = client.pdfOperations.merge({ input: ['file_avyrvozb9302uwhq'] }); const rawResponse = await responsePromise.asResponse(); @@ -45,7 +45,7 @@ describe('resource pdfOperations', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - // skipped: tests are disabled for the time being + // Prism tests are disabled test.skip('merge: required and optional params', async () => { const response = await client.pdfOperations.merge({ input: ['file_avyrvozb9302uwhq'], @@ -54,7 +54,7 @@ describe('resource pdfOperations', () => { }); }); - // skipped: tests are disabled for the time being + // Prism tests are disabled test.skip('render: only required params', async () => { const responsePromise = client.pdfOperations.render({ input: 'file_avyrvozb9302uwhq' }); const rawResponse = await responsePromise.asResponse(); @@ -66,7 +66,7 @@ describe('resource pdfOperations', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - // skipped: tests are disabled for the time being + // Prism tests are disabled test.skip('render: required and optional params', async () => { const response = await client.pdfOperations.render({ input: 'file_avyrvozb9302uwhq', @@ -77,7 +77,7 @@ describe('resource pdfOperations', () => { }); }); - // skipped: tests are disabled for the time being + // Prism tests are disabled test.skip('split: only required params', async () => { const responsePromise = client.pdfOperations.split({ input: 'file_avyrvozb9302uwhq' }); const rawResponse = await responsePromise.asResponse(); @@ -89,7 +89,7 @@ describe('resource pdfOperations', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - // skipped: tests are disabled for the time being + // Prism tests are disabled test.skip('split: required and optional params', async () => { const response = await client.pdfOperations.split({ input: 'file_avyrvozb9302uwhq', diff --git a/tests/api-resources/tasks.test.ts b/tests/api-resources/tasks.test.ts index d935f79..ba551fa 100644 --- a/tests/api-resources/tasks.test.ts +++ b/tests/api-resources/tasks.test.ts @@ -8,7 +8,7 @@ const client = new ScanDocuments({ }); describe('resource tasks', () => { - // skipped: tests are disabled for the time being + // Prism tests are disabled test.skip('retrieve', async () => { const responsePromise = client.tasks.retrieve('task_euyrvozb9302uwhq'); const rawResponse = await responsePromise.asResponse(); @@ -20,7 +20,7 @@ describe('resource tasks', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - // skipped: tests are disabled for the time being + // Prism tests are disabled test.skip('list', async () => { const responsePromise = client.tasks.list(); const rawResponse = await responsePromise.asResponse(); @@ -32,7 +32,7 @@ describe('resource tasks', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - // skipped: tests are disabled for the time being + // Prism tests are disabled test.skip('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( From 938a40bc3dc1b8f4cacdea781c23dea0680ac1eb Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 14 Aug 2025 04:40:44 +0000 Subject: [PATCH 72/91] chore(mcp): minor cleanup of types and package.json --- packages/mcp-server/package.json | 1 + packages/mcp-server/src/http.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/mcp-server/package.json b/packages/mcp-server/package.json index ae0f2ed..b9bbd88 100644 --- a/packages/mcp-server/package.json +++ b/packages/mcp-server/package.json @@ -42,6 +42,7 @@ "devDependencies": { "@types/jest": "^29.4.0", "@types/express": "^5.0.3", + "@types/yargs": "^17.0.8", "@typescript-eslint/eslint-plugin": "8.31.1", "@typescript-eslint/parser": "8.31.1", "eslint": "^8.49.0", diff --git a/packages/mcp-server/src/http.ts b/packages/mcp-server/src/http.ts index 900e131..e188c9e 100644 --- a/packages/mcp-server/src/http.ts +++ b/packages/mcp-server/src/http.ts @@ -69,7 +69,7 @@ const del = async (req: express.Request, res: express.Response) => { }); }; -export const streamableHTTPApp = (options: McpOptions) => { +export const streamableHTTPApp = (options: McpOptions): express.Express => { const app = express(); app.use(express.json()); From 488ee1c68366d5253d75565838c2c3447af525b1 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 15 Aug 2025 03:14:40 +0000 Subject: [PATCH 73/91] fix(mcp): generate additionalProperties=true for map schemas to avoid validation issues --- .../src/tools/image-operations/extract-text-image-operations.ts | 2 ++ .../src/tools/image-operations/warp-image-operations.ts | 1 + 2 files changed, 3 insertions(+) diff --git a/packages/mcp-server/src/tools/image-operations/extract-text-image-operations.ts b/packages/mcp-server/src/tools/image-operations/extract-text-image-operations.ts index cdb16c5..a647ae5 100644 --- a/packages/mcp-server/src/tools/image-operations/extract-text-image-operations.ts +++ b/packages/mcp-server/src/tools/image-operations/extract-text-image-operations.ts @@ -115,6 +115,7 @@ export const tool: Tool = { }, example: { type: 'object', + additionalProperties: true, }, format: { type: 'string', @@ -124,6 +125,7 @@ export const tool: Tool = { }, properties: { type: 'object', + additionalProperties: true, }, required: { type: 'array', diff --git a/packages/mcp-server/src/tools/image-operations/warp-image-operations.ts b/packages/mcp-server/src/tools/image-operations/warp-image-operations.ts index c0ffe87..5f8ed48 100644 --- a/packages/mcp-server/src/tools/image-operations/warp-image-operations.ts +++ b/packages/mcp-server/src/tools/image-operations/warp-image-operations.ts @@ -30,6 +30,7 @@ export const tool: Tool = { description: 'Coordinates of the 4 vertices of the quadrilateral to warp the image to.', items: { type: 'object', + additionalProperties: true, }, }, callback_url: { From 64f8b3a076b881b43878aa2e78c2942a6b53d98d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 15 Aug 2025 03:18:56 +0000 Subject: [PATCH 74/91] chore(mcp): document remote server in README.md --- packages/mcp-server/README.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/packages/mcp-server/README.md b/packages/mcp-server/README.md index 0e6cc64..606c79a 100644 --- a/packages/mcp-server/README.md +++ b/packages/mcp-server/README.md @@ -126,6 +126,30 @@ over time, you can manually enable or disable certain capabilities: --resource=cards,accounts --operation=read --tag=kyc --no-tool=create_cards ``` +## Running remotely + +Launching the client with `--transport=http` launches the server as a remote server using Streamable HTTP transport. The `--port` setting can choose the port it will run on, and the `--socket` setting allows it to run on a Unix socket. + +Authorization can be provided via the following headers: +| Header | Equivalent client option | Security scheme | +| ----------- | ------------------------ | --------------- | +| `x-api-key` | `apiKey` | ApiKeyAuth | + +A configuration JSON for this server might look like this: + +```json +{ + "mcpServers": { + "scan_documents_api": { + "url": "http://localhost:3000", # or wherever the server is hosted + "headers": { + 'x-api-key': 'My API Key' + } + } + } +} +``` + ## Importing the tools and server individually ```js From b435ab1ef8e26e20a35842579846c87cd20ff4be Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 16 Aug 2025 03:48:20 +0000 Subject: [PATCH 75/91] chore(deps): update dependency @types/node to v20.17.58 --- yarn.lock | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/yarn.lock b/yarn.lock index 58c08d5..fd164dc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -938,11 +938,11 @@ undici-types "~5.26.4" "@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== + version "20.19.11" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.19.11.tgz#728cab53092bd5f143beed7fbba7ba99de3c16c4" + integrity sha512-uug3FEEGv0r+jrecvUUpbY8lLisvIjg6AAic6a2bSP5OEOLeJsDSnvhCDov7ipFFMXS3orMpzlmi0ZcuGkBbow== dependencies: - undici-types "~6.19.2" + undici-types "~6.21.0" "@types/stack-utils@^2.0.0": version "2.0.3" @@ -3285,6 +3285,7 @@ ts-node@^10.5.0: "tsc-multi@https://github.com/stainless-api/tsc-multi/releases/download/v1.1.8/tsc-multi.tgz": version "1.1.8" + uid f544b359b8f05e607771ffacc280e58201476b04 resolved "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.8/tsc-multi.tgz#f544b359b8f05e607771ffacc280e58201476b04" dependencies: debug "^4.3.7" @@ -3353,10 +3354,10 @@ undici-types@~5.26.4: resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== -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== +undici-types@~6.21.0: + version "6.21.0" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.21.0.tgz#691d00af3909be93a7faa13be61b3a5b50ef12cb" + integrity sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ== unicode-emoji-modifier-base@^1.0.0: version "1.0.0" From b821690f1b0a2494dcb6b2ab0643a212b4a040dc Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 16 Aug 2025 03:49:23 +0000 Subject: [PATCH 76/91] chore(mcp): update README --- packages/mcp-server/README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/mcp-server/README.md b/packages/mcp-server/README.md index 606c79a..8b55915 100644 --- a/packages/mcp-server/README.md +++ b/packages/mcp-server/README.md @@ -135,15 +135,15 @@ Authorization can be provided via the following headers: | ----------- | ------------------------ | --------------- | | `x-api-key` | `apiKey` | ApiKeyAuth | -A configuration JSON for this server might look like this: +A configuration JSON for this server might look like this, assuming the server is hosted at `http://localhost:3000`: ```json { "mcpServers": { "scan_documents_api": { - "url": "http://localhost:3000", # or wherever the server is hosted + "url": "http://localhost:3000", "headers": { - 'x-api-key': 'My API Key' + "x-api-key": "My API Key" } } } From 5a0343c3751c96f3637abfd0ea84df271abf70a2 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 16 Aug 2025 03:53:08 +0000 Subject: [PATCH 77/91] chore(internal): formatting change --- src/client.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/client.ts b/src/client.ts index eba1ad8..bb7e9b6 100644 --- a/src/client.ts +++ b/src/client.ts @@ -755,11 +755,13 @@ export class ScanDocuments { imageOperations: API.ImageOperations = new API.ImageOperations(this); pdfOperations: API.PdfOperations = new API.PdfOperations(this); } + ScanDocuments.Files = Files; ScanDocuments.Tasks = Tasks; ScanDocuments.Events = Events; ScanDocuments.ImageOperations = ImageOperations; ScanDocuments.PdfOperations = PdfOperations; + export declare namespace ScanDocuments { export type RequestOptions = Opts.RequestOptions; From a72cd4273cb2efc360656de84e17c94d2ba21c25 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 19 Aug 2025 03:06:31 +0000 Subject: [PATCH 78/91] feat(mcp): parse query string as mcp client options in mcp server --- packages/mcp-server/README.md | 13 ++ packages/mcp-server/package.json | 8 +- packages/mcp-server/src/compat.ts | 4 +- packages/mcp-server/src/http.ts | 25 ++- packages/mcp-server/src/index.ts | 4 +- packages/mcp-server/src/options.ts | 121 ++++++++++- packages/mcp-server/tests/options.test.ts | 240 +++++++++++++++++++++- packages/mcp-server/yarn.lock | 116 +++++++++-- 8 files changed, 499 insertions(+), 32 deletions(-) diff --git a/packages/mcp-server/README.md b/packages/mcp-server/README.md index 8b55915..b0aab00 100644 --- a/packages/mcp-server/README.md +++ b/packages/mcp-server/README.md @@ -150,6 +150,19 @@ A configuration JSON for this server might look like this, assuming the server i } ``` +The command-line arguments for filtering tools and specifying clients can also be used as query parameters in the URL. +For example, to exclude specific tools while including others, use the URL: + +``` +http://localhost:3000?resource=cards&resource=accounts&no_tool=create_cards +``` + +Or, to configure for the Cursor client, with a custom max tool name length, use the URL: + +``` +http://localhost:3000?client=cursor&capability=tool-name-length%3D40 +``` + ## Importing the tools and server individually ```js diff --git a/packages/mcp-server/package.json b/packages/mcp-server/package.json index b9bbd88..2cd0ed0 100644 --- a/packages/mcp-server/package.json +++ b/packages/mcp-server/package.json @@ -28,20 +28,22 @@ }, "dependencies": { "scan-documents": "file:../../dist/", + "@cloudflare/cabidela": "^0.2.4", "@modelcontextprotocol/sdk": "^1.11.5", "express": "^5.1.0", "jq-web": "https://github.com/stainless-api/jq-web/releases/download/v0.8.6/jq-web.tar.gz", + "qs": "^6.14.0", "yargs": "^17.7.2", - "@cloudflare/cabidela": "^0.2.4", "zod": "^3.25.20", - "zod-to-json-schema": "^3.24.5" + "zod-to-json-schema": "^3.24.5", + "zod-validation-error": "^4.0.1" }, "bin": { "mcp-server": "dist/index.js" }, "devDependencies": { - "@types/jest": "^29.4.0", "@types/express": "^5.0.3", + "@types/jest": "^29.4.0", "@types/yargs": "^17.0.8", "@typescript-eslint/eslint-plugin": "8.31.1", "@typescript-eslint/parser": "8.31.1", diff --git a/packages/mcp-server/src/compat.ts b/packages/mcp-server/src/compat.ts index 7afd77f..1df7a7a 100644 --- a/packages/mcp-server/src/compat.ts +++ b/packages/mcp-server/src/compat.ts @@ -1,4 +1,5 @@ import { Tool } from '@modelcontextprotocol/sdk/types.js'; +import { z } from 'zod'; import { Endpoint } from './tools'; export interface ClientCapabilities { @@ -19,7 +20,8 @@ export const defaultClientCapabilities: ClientCapabilities = { toolNameLength: undefined, }; -export type ClientType = 'openai-agents' | 'claude' | 'claude-code' | 'cursor'; +export const ClientType = z.enum(['openai-agents', 'claude', 'claude-code', 'cursor']); +export type ClientType = z.infer; // Client presets for compatibility // Note that these could change over time as models get better, so this is diff --git a/packages/mcp-server/src/http.ts b/packages/mcp-server/src/http.ts index e188c9e..ca6d3d2 100644 --- a/packages/mcp-server/src/http.ts +++ b/packages/mcp-server/src/http.ts @@ -4,13 +4,33 @@ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp'; import { StreamableHTTPServerTransport } from '@modelcontextprotocol/sdk/server/streamableHttp.js'; import express from 'express'; -import { McpOptions } from './options'; +import { fromError } from 'zod-validation-error/v3'; +import { McpOptions, parseQueryOptions } from './options'; import { initMcpServer, newMcpServer } from './server'; import { parseAuthHeaders } from './headers'; import { Endpoint } from './tools'; -const newServer = (mcpOptions: McpOptions, req: express.Request, res: express.Response): McpServer | null => { +const newServer = ( + defaultMcpOptions: McpOptions, + req: express.Request, + res: express.Response, +): McpServer | null => { const server = newMcpServer(); + + let mcpOptions: McpOptions; + try { + mcpOptions = parseQueryOptions(defaultMcpOptions, req.query); + } catch (error) { + res.status(400).json({ + jsonrpc: '2.0', + error: { + code: -32000, + message: `Invalid request: ${fromError(error)}`, + }, + }); + return null; + } + try { const authOptions = parseAuthHeaders(req); initMcpServer({ @@ -71,6 +91,7 @@ const del = async (req: express.Request, res: express.Response) => { export const streamableHTTPApp = (options: McpOptions): express.Express => { const app = express(); + app.set('query parser', 'extended'); app.use(express.json()); app.get('/', get); diff --git a/packages/mcp-server/src/index.ts b/packages/mcp-server/src/index.ts index 4c71a3b..05b2ba6 100644 --- a/packages/mcp-server/src/index.ts +++ b/packages/mcp-server/src/index.ts @@ -2,7 +2,7 @@ import { selectTools } from './server'; import { Endpoint, endpoints } from './tools'; -import { McpOptions, parseOptions } from './options'; +import { McpOptions, parseCLIOptions } from './options'; import { launchStdioServer } from './stdio'; import { launchStreamableHTTPServer } from './http'; @@ -40,7 +40,7 @@ if (require.main === module) { function parseOptionsOrError() { try { - return parseOptions(); + return parseCLIOptions(); } catch (error) { console.error('Error parsing options:', error); process.exit(1); diff --git a/packages/mcp-server/src/options.ts b/packages/mcp-server/src/options.ts index c290ca5..0768d93 100644 --- a/packages/mcp-server/src/options.ts +++ b/packages/mcp-server/src/options.ts @@ -1,5 +1,7 @@ +import qs from 'qs'; import yargs from 'yargs'; import { hideBin } from 'yargs/helpers'; +import z from 'zod'; import { endpoints, Filter } from './tools'; import { ClientCapabilities, knownClients, ClientType } from './compat'; @@ -47,7 +49,7 @@ function parseCapabilityValue(cap: string): { name: Capability; value?: number } return { name: cap as Capability }; } -export function parseOptions(): CLIOptions { +export function parseCLIOptions(): CLIOptions { const opts = yargs(hideBin(process.argv)) .option('tools', { type: 'string', @@ -271,6 +273,123 @@ export function parseOptions(): CLIOptions { }; } +const coerceArray = (zodType: T) => + z.preprocess( + (val) => + Array.isArray(val) ? val + : val ? [val] + : val, + z.array(zodType).optional(), + ); + +const QueryOptions = z.object({ + tools: coerceArray(z.enum(['dynamic', 'all'])).describe('Use dynamic tools or all tools'), + no_tools: coerceArray(z.enum(['dynamic', 'all'])).describe('Do not use dynamic tools or all tools'), + tool: coerceArray(z.string()).describe('Include tools matching the specified names'), + resource: coerceArray(z.string()).describe('Include tools matching the specified resources'), + operation: coerceArray(z.enum(['read', 'write'])).describe( + 'Include tools matching the specified operations', + ), + tag: coerceArray(z.string()).describe('Include tools with the specified tags'), + no_tool: coerceArray(z.string()).describe('Exclude tools matching the specified names'), + no_resource: coerceArray(z.string()).describe('Exclude tools matching the specified resources'), + no_operation: coerceArray(z.enum(['read', 'write'])).describe( + 'Exclude tools matching the specified operations', + ), + no_tag: coerceArray(z.string()).describe('Exclude tools with the specified tags'), + client: ClientType.optional().describe('Specify the MCP client being used'), + capability: coerceArray(z.string()).describe('Specify client capabilities'), + no_capability: coerceArray(z.enum(CAPABILITY_CHOICES)).describe('Unset client capabilities'), +}); + +export function parseQueryOptions(defaultOptions: McpOptions, query: unknown): McpOptions { + const queryObject = typeof query === 'string' ? qs.parse(query) : query; + const queryOptions = QueryOptions.parse(queryObject); + + const filters: Filter[] = [...defaultOptions.filters]; + + for (const resource of queryOptions.resource || []) { + filters.push({ type: 'resource', op: 'include', value: resource }); + } + for (const operation of queryOptions.operation || []) { + filters.push({ type: 'operation', op: 'include', value: operation }); + } + for (const tag of queryOptions.tag || []) { + filters.push({ type: 'tag', op: 'include', value: tag }); + } + for (const tool of queryOptions.tool || []) { + filters.push({ type: 'tool', op: 'include', value: tool }); + } + for (const resource of queryOptions.no_resource || []) { + filters.push({ type: 'resource', op: 'exclude', value: resource }); + } + for (const operation of queryOptions.no_operation || []) { + filters.push({ type: 'operation', op: 'exclude', value: operation }); + } + for (const tag of queryOptions.no_tag || []) { + filters.push({ type: 'tag', op: 'exclude', value: tag }); + } + for (const tool of queryOptions.no_tool || []) { + filters.push({ type: 'tool', op: 'exclude', value: tool }); + } + + // Parse client capabilities + const clientCapabilities: ClientCapabilities = { + topLevelUnions: true, + validJson: true, + refs: true, + unions: true, + formats: true, + toolNameLength: undefined, + ...defaultOptions.capabilities, + }; + + for (const cap of queryOptions.capability || []) { + const parsed = parseCapabilityValue(cap); + if (parsed.name === 'top-level-unions') { + clientCapabilities.topLevelUnions = true; + } else if (parsed.name === 'valid-json') { + clientCapabilities.validJson = true; + } else if (parsed.name === 'refs') { + clientCapabilities.refs = true; + } else if (parsed.name === 'unions') { + clientCapabilities.unions = true; + } else if (parsed.name === 'formats') { + clientCapabilities.formats = true; + } else if (parsed.name === 'tool-name-length') { + clientCapabilities.toolNameLength = parsed.value; + } + } + + for (const cap of queryOptions.no_capability || []) { + if (cap === 'top-level-unions') { + clientCapabilities.topLevelUnions = false; + } else if (cap === 'valid-json') { + clientCapabilities.validJson = false; + } else if (cap === 'refs') { + clientCapabilities.refs = false; + } else if (cap === 'unions') { + clientCapabilities.unions = false; + } else if (cap === 'formats') { + clientCapabilities.formats = false; + } else if (cap === 'tool-name-length') { + clientCapabilities.toolNameLength = undefined; + } + } + + return { + client: queryOptions.client ?? defaultOptions.client, + includeDynamicTools: + defaultOptions.includeDynamicTools ?? + (queryOptions.tools?.includes('dynamic') && !queryOptions.no_tools?.includes('dynamic')), + includeAllTools: + defaultOptions.includeAllTools ?? + (queryOptions.tools?.includes('all') && !queryOptions.no_tools?.includes('all')), + filters, + capabilities: clientCapabilities, + }; +} + function getCapabilitiesExplanation(): string { return ` Client Capabilities Explanation: diff --git a/packages/mcp-server/tests/options.test.ts b/packages/mcp-server/tests/options.test.ts index 264aca5..08ea1f1 100644 --- a/packages/mcp-server/tests/options.test.ts +++ b/packages/mcp-server/tests/options.test.ts @@ -1,4 +1,4 @@ -import { parseOptions } from '../src/options'; +import { parseCLIOptions, parseQueryOptions } from '../src/options'; import { Filter } from '../src/tools'; import { parseEmbeddedJSON } from '../src/compat'; @@ -11,7 +11,7 @@ const mockArgv = (args: string[]) => { }; }; -describe('parseOptions', () => { +describe('parseCLIOptions', () => { it('should parse basic filter options', () => { const cleanup = mockArgv([ '--tool=test-tool', @@ -20,7 +20,7 @@ describe('parseOptions', () => { '--tag=test-tag', ]); - const result = parseOptions(); + const result = parseCLIOptions(); expect(result.filters).toEqual([ { type: 'tag', op: 'include', value: 'test-tag' }, @@ -52,7 +52,7 @@ describe('parseOptions', () => { '--no-tag=exclude-tag', ]); - const result = parseOptions(); + const result = parseCLIOptions(); expect(result.filters).toEqual([ { type: 'tag', op: 'exclude', value: 'exclude-tag' }, @@ -76,7 +76,7 @@ describe('parseOptions', () => { it('should parse client presets', () => { const cleanup = mockArgv(['--client=openai-agents']); - const result = parseOptions(); + const result = parseCLIOptions(); expect(result.client).toEqual('openai-agents'); @@ -92,7 +92,7 @@ describe('parseOptions', () => { '--capability=tool-name-length=40', ]); - const result = parseOptions(); + const result = parseCLIOptions(); expect(result.capabilities).toEqual({ topLevelUnions: true, @@ -109,7 +109,7 @@ describe('parseOptions', () => { it('should handle list option', () => { const cleanup = mockArgv(['--list']); - const result = parseOptions(); + const result = parseCLIOptions(); expect(result.list).toBe(true); @@ -119,7 +119,7 @@ describe('parseOptions', () => { it('should handle multiple filters of the same type', () => { const cleanup = mockArgv(['--tool=tool1', '--tool=tool2', '--resource=res1', '--resource=res2']); - const result = parseOptions(); + const result = parseCLIOptions(); expect(result.filters).toEqual([ { type: 'resource', op: 'include', value: 'res1' }, @@ -138,7 +138,7 @@ describe('parseOptions', () => { '--capability=top-level-unions,valid-json,unions', ]); - const result = parseOptions(); + const result = parseCLIOptions(); expect(result.filters).toEqual([ { type: 'resource', op: 'include', value: 'res1' }, @@ -166,7 +166,7 @@ describe('parseOptions', () => { const originalError = console.error; console.error = jest.fn(); - expect(() => parseOptions()).toThrow(); + expect(() => parseCLIOptions()).toThrow(); console.error = originalError; cleanup(); @@ -179,13 +179,231 @@ describe('parseOptions', () => { const originalError = console.error; console.error = jest.fn(); - expect(() => parseOptions()).toThrow(); + expect(() => parseCLIOptions()).toThrow(); console.error = originalError; cleanup(); }); }); +describe('parseQueryOptions', () => { + const defaultOptions = { + client: undefined, + includeDynamicTools: undefined, + includeAllTools: undefined, + filters: [], + capabilities: { + topLevelUnions: true, + validJson: true, + refs: true, + unions: true, + formats: true, + toolNameLength: undefined, + }, + }; + + it('should parse basic filter options from query string', () => { + const query = 'tool=test-tool&resource=test-resource&operation=read&tag=test-tag'; + const result = parseQueryOptions(defaultOptions, query); + + expect(result.filters).toEqual([ + { type: 'resource', op: 'include', value: 'test-resource' }, + { type: 'operation', op: 'include', value: 'read' }, + { type: 'tag', op: 'include', value: 'test-tag' }, + { type: 'tool', op: 'include', value: 'test-tool' }, + ]); + + expect(result.capabilities).toEqual({ + topLevelUnions: true, + validJson: true, + refs: true, + unions: true, + formats: true, + toolNameLength: undefined, + }); + }); + + it('should parse exclusion filters from query string', () => { + const query = 'no_tool=exclude-tool&no_resource=exclude-resource&no_operation=write&no_tag=exclude-tag'; + const result = parseQueryOptions(defaultOptions, query); + + expect(result.filters).toEqual([ + { type: 'resource', op: 'exclude', value: 'exclude-resource' }, + { type: 'operation', op: 'exclude', value: 'write' }, + { type: 'tag', op: 'exclude', value: 'exclude-tag' }, + { type: 'tool', op: 'exclude', value: 'exclude-tool' }, + ]); + }); + + it('should parse client option from query string', () => { + const query = 'client=openai-agents'; + const result = parseQueryOptions(defaultOptions, query); + + expect(result.client).toBe('openai-agents'); + }); + + it('should parse client capabilities from query string', () => { + const query = 'capability=top-level-unions&capability=valid-json&capability=tool-name-length%3D40'; + const result = parseQueryOptions(defaultOptions, query); + + expect(result.capabilities).toEqual({ + topLevelUnions: true, + validJson: true, + refs: true, + unions: true, + formats: true, + toolNameLength: 40, + }); + }); + + it('should parse no-capability options from query string', () => { + const query = 'no_capability=top-level-unions&no_capability=refs&no_capability=formats'; + const result = parseQueryOptions(defaultOptions, query); + + expect(result.capabilities).toEqual({ + topLevelUnions: false, + validJson: true, + refs: false, + unions: true, + formats: false, + toolNameLength: undefined, + }); + }); + + it('should parse tools options from query string', () => { + const query = 'tools=dynamic&tools=all'; + const result = parseQueryOptions(defaultOptions, query); + + expect(result.includeDynamicTools).toBe(true); + expect(result.includeAllTools).toBe(true); + }); + + it('should parse no-tools options from query string', () => { + const query = 'tools=dynamic&tools=all&no_tools=dynamic'; + const result = parseQueryOptions(defaultOptions, query); + + expect(result.includeDynamicTools).toBe(false); + expect(result.includeAllTools).toBe(true); + }); + + it('should handle array values in query string', () => { + const query = 'tool[]=tool1&tool[]=tool2&resource[]=res1&resource[]=res2'; + const result = parseQueryOptions(defaultOptions, query); + + expect(result.filters).toEqual([ + { type: 'resource', op: 'include', value: 'res1' }, + { type: 'resource', op: 'include', value: 'res2' }, + { type: 'tool', op: 'include', value: 'tool1' }, + { type: 'tool', op: 'include', value: 'tool2' }, + ]); + }); + + it('should merge with default options', () => { + const defaultWithFilters = { + ...defaultOptions, + filters: [{ type: 'tag' as const, op: 'include' as const, value: 'existing-tag' }], + client: 'cursor' as const, + includeDynamicTools: true, + }; + + const query = 'tool=new-tool&resource=new-resource'; + const result = parseQueryOptions(defaultWithFilters, query); + + expect(result.filters).toEqual([ + { type: 'tag', op: 'include', value: 'existing-tag' }, + { type: 'resource', op: 'include', value: 'new-resource' }, + { type: 'tool', op: 'include', value: 'new-tool' }, + ]); + + expect(result.client).toBe('cursor'); + expect(result.includeDynamicTools).toBe(true); + }); + + it('should override client from default options', () => { + const defaultWithClient = { + ...defaultOptions, + client: 'cursor' as const, + }; + + const query = 'client=openai-agents'; + const result = parseQueryOptions(defaultWithClient, query); + + expect(result.client).toBe('openai-agents'); + }); + + it('should merge capabilities with default options', () => { + const defaultWithCapabilities = { + ...defaultOptions, + capabilities: { + topLevelUnions: false, + validJson: false, + refs: true, + unions: true, + formats: true, + toolNameLength: 30, + }, + }; + + const query = 'capability=top-level-unions&no_capability=refs'; + const result = parseQueryOptions(defaultWithCapabilities, query); + + expect(result.capabilities).toEqual({ + topLevelUnions: true, + validJson: false, + refs: false, + unions: true, + formats: true, + toolNameLength: 30, + }); + }); + + it('should handle empty query string', () => { + const query = ''; + const result = parseQueryOptions(defaultOptions, query); + + expect(result).toEqual(defaultOptions); + }); + + it('should handle invalid query string gracefully', () => { + const query = 'invalid=value&operation=invalid-operation'; + + // Should throw due to Zod validation for invalid operation + expect(() => parseQueryOptions(defaultOptions, query)).toThrow(); + }); + + it('should preserve default undefined values when not specified', () => { + const defaultWithUndefined = { + ...defaultOptions, + client: undefined, + includeDynamicTools: undefined, + includeAllTools: undefined, + }; + + const query = 'tool=test-tool'; + const result = parseQueryOptions(defaultWithUndefined, query); + + expect(result.client).toBeUndefined(); + expect(result.includeDynamicTools).toBeFalsy(); + expect(result.includeAllTools).toBeFalsy(); + }); + + it('should handle complex query with mixed include and exclude filters', () => { + const query = + 'tool=include-tool&no_tool=exclude-tool&resource=include-res&no_resource=exclude-res&operation=read&tag=include-tag&no_tag=exclude-tag'; + const result = parseQueryOptions(defaultOptions, query); + + expect(result.filters).toEqual([ + { type: 'resource', op: 'include', value: 'include-res' }, + { type: 'operation', op: 'include', value: 'read' }, + { type: 'tag', op: 'include', value: 'include-tag' }, + { type: 'tool', op: 'include', value: 'include-tool' }, + { type: 'resource', op: 'exclude', value: 'exclude-res' }, + { type: 'tag', op: 'exclude', value: 'exclude-tag' }, + { type: 'tool', op: 'exclude', value: 'exclude-tool' }, + ]); + }); +}); + describe('parseEmbeddedJSON', () => { it('should not change non-string values', () => { const args = { diff --git a/packages/mcp-server/yarn.lock b/packages/mcp-server/yarn.lock index 9970ec3..707a2de 100644 --- a/packages/mcp-server/yarn.lock +++ b/packages/mcp-server/yarn.lock @@ -584,15 +584,17 @@ "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" -"@modelcontextprotocol/sdk@^1.6.1": - version "1.11.1" - resolved "https://registry.yarnpkg.com/@modelcontextprotocol/sdk/-/sdk-1.11.1.tgz#c7f4a1432872ef10130f5d9b0072060c17a3946b" - integrity sha512-9LfmxKTb1v+vUS1/emSk1f5ePmTLkb9Le9AxOB5T0XM59EUumwcS45z05h7aiZx3GI0Bl7mjb3FMEglYj+acuQ== +"@modelcontextprotocol/sdk@^1.11.5": + version "1.17.3" + resolved "https://registry.yarnpkg.com/@modelcontextprotocol/sdk/-/sdk-1.17.3.tgz#cf92354220f0183d28179e96a9bf3a8f6d3211ae" + integrity sha512-JPwUKWSsbzx+DLFznf/QZ32Qa+ptfbUlHhRLrBQBAFu9iI1iYvizM4p+zhhRDceSsPutXp4z+R/HPVphlIiclg== dependencies: + ajv "^6.12.6" content-type "^1.0.5" cors "^2.8.5" - cross-spawn "^7.0.3" + cross-spawn "^7.0.5" eventsource "^3.0.2" + eventsource-parser "^3.0.0" express "^5.0.1" express-rate-limit "^7.5.0" pkce-challenge "^5.0.0" @@ -708,6 +710,40 @@ dependencies: "@babel/types" "^7.20.7" +"@types/body-parser@*": + version "1.19.6" + resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.19.6.tgz#1859bebb8fd7dac9918a45d54c1971ab8b5af474" + integrity sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g== + dependencies: + "@types/connect" "*" + "@types/node" "*" + +"@types/connect@*": + version "3.4.38" + resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.38.tgz#5ba7f3bc4fbbdeaff8dded952e5ff2cc53f8d858" + integrity sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug== + dependencies: + "@types/node" "*" + +"@types/express-serve-static-core@^5.0.0": + version "5.0.7" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-5.0.7.tgz#2fa94879c9d46b11a5df4c74ac75befd6b283de6" + integrity sha512-R+33OsgWw7rOhD1emjU7dzCDHucJrgJXMA5PYCzJxVil0dsyx5iBEPHqpPfiKNJQb7lZ1vxwoLR4Z87bBUpeGQ== + dependencies: + "@types/node" "*" + "@types/qs" "*" + "@types/range-parser" "*" + "@types/send" "*" + +"@types/express@^5.0.3": + version "5.0.3" + resolved "https://registry.yarnpkg.com/@types/express/-/express-5.0.3.tgz#6c4bc6acddc2e2a587142e1d8be0bce20757e956" + integrity sha512-wGA0NX93b19/dZC1J18tKWVIYWyyF2ZjT9vin/NRu0qzzvfVzWjs04iq2rQ3H65vCTQYlRqs3YHfY7zjdV+9Kw== + dependencies: + "@types/body-parser" "*" + "@types/express-serve-static-core" "^5.0.0" + "@types/serve-static" "*" + "@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" @@ -715,6 +751,11 @@ dependencies: "@types/node" "*" +"@types/http-errors@*": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@types/http-errors/-/http-errors-2.0.5.tgz#5b749ab2b16ba113423feb1a64a95dcd30398472" + integrity sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg== + "@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": version "2.0.6" resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz#7739c232a1fee9b4d3ce8985f314c0c6d33549d7" @@ -742,6 +783,11 @@ expect "^29.0.0" pretty-format "^29.0.0" +"@types/mime@^1": + version "1.3.5" + resolved "https://registry.yarnpkg.com/@types/mime/-/mime-1.3.5.tgz#1ef302e01cf7d2b5a0fa526790c9123bf1d06690" + integrity sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w== + "@types/node@*": version "22.15.17" resolved "https://registry.yarnpkg.com/@types/node/-/node-22.15.17.tgz#355ccec95f705b664e4332bb64a7f07db30b7055" @@ -749,6 +795,33 @@ dependencies: undici-types "~6.21.0" +"@types/qs@*": + version "6.14.0" + resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.14.0.tgz#d8b60cecf62f2db0fb68e5e006077b9178b85de5" + integrity sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ== + +"@types/range-parser@*": + version "1.2.7" + resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.7.tgz#50ae4353eaaddc04044279812f52c8c65857dbcb" + integrity sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ== + +"@types/send@*": + version "0.17.5" + resolved "https://registry.yarnpkg.com/@types/send/-/send-0.17.5.tgz#d991d4f2b16f2b1ef497131f00a9114290791e74" + integrity sha512-z6F2D3cOStZvuk2SaP6YrwkNO65iTZcwA2ZkSABegdkAh/lf+Aa/YQndZVfmEXT5vgAp6zv06VQ3ejSVjAny4w== + dependencies: + "@types/mime" "^1" + "@types/node" "*" + +"@types/serve-static@*": + version "1.15.8" + resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.15.8.tgz#8180c3fbe4a70e8f00b9f70b9ba7f08f35987877" + integrity sha512-roei0UY3LhpOJvjbIP6ZZFngyLKl5dskOtDhxY5THRSpO+ZI+nzJ+m5yUMzGrp89YRa7lvknKkMYjqQFGwA7Sg== + dependencies: + "@types/http-errors" "*" + "@types/node" "*" + "@types/send" "*" + "@types/stack-utils@^2.0.0": version "2.0.3" resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.3.tgz#6209321eb2c1712a7e7466422b8cb1fc0d9dd5d8" @@ -885,7 +958,7 @@ aggregate-error@^3.0.0: clean-stack "^2.0.0" indent-string "^4.0.0" -ajv@^6.12.4: +ajv@^6.12.4, ajv@^6.12.6: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -1246,7 +1319,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.2, cross-spawn@^7.0.3, cross-spawn@^7.0.5: version "7.0.6" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== @@ -1514,6 +1587,11 @@ etag@^1.8.1: resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" integrity sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg== +eventsource-parser@^3.0.0: + version "3.0.3" + resolved "https://registry.yarnpkg.com/eventsource-parser/-/eventsource-parser-3.0.3.tgz#e9af1d40b77e6268cdcbc767321e8b9f066adea8" + integrity sha512-nVpZkTMM9rF6AQ9gPJpFsNAMt48wIzB5TQgiTLdHiuO8XEDhUgZEhqKlZWXbIzo9VmJ/HvysHqEaVeD5v9TPvA== + eventsource-parser@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/eventsource-parser/-/eventsource-parser-3.0.1.tgz#5e358dba9a55ba64ca90da883c4ca35bd82467bd" @@ -1562,7 +1640,7 @@ express-rate-limit@^7.5.0: resolved "https://registry.yarnpkg.com/express-rate-limit/-/express-rate-limit-7.5.0.tgz#6a67990a724b4fbbc69119419feef50c51e8b28f" integrity sha512-eB5zbQh5h+VenMPM3fh+nw1YExi5nMr6HUCR62ELSP11huvxm/Uir1H1QEyTkk5QX6A58pX6NmaTMceKZ0Eodg== -express@^5.0.1: +express@^5.0.1, express@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/express/-/express-5.1.0.tgz#d31beaf715a0016f0d53f47d3b4d7acf28c75cc9" integrity sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA== @@ -2404,6 +2482,10 @@ jest@^29.4.0: import-local "^3.0.2" jest-cli "^29.7.0" +"jq-web@https://github.com/stainless-api/jq-web/releases/download/v0.8.6/jq-web.tar.gz": + version "0.8.6" + resolved "https://github.com/stainless-api/jq-web/releases/download/v0.8.6/jq-web.tar.gz#14d0e126987736e82e964d675c3838b5944faa6f" + js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" @@ -3305,9 +3387,9 @@ ts-node@^10.5.0: v8-compile-cache-lib "^3.0.1" yn "3.1.1" -"tsc-multi@https://github.com/stainless-api/tsc-multi/releases/download/v1.1.7/tsc-multi.tgz": - version "1.1.7" - resolved "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.7/tsc-multi.tgz#52f40adf8b808bd0b633346d11cc4a8aeea465cd" +"tsc-multi@https://github.com/stainless-api/tsc-multi/releases/download/v1.1.8/tsc-multi.tgz": + version "1.1.8" + resolved "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.8/tsc-multi.tgz#f544b359b8f05e607771ffacc280e58201476b04" dependencies: debug "^4.3.7" fast-glob "^3.3.2" @@ -3508,7 +3590,17 @@ zod-to-json-schema@^3.24.1, zod-to-json-schema@^3.24.5: resolved "https://registry.yarnpkg.com/zod-to-json-schema/-/zod-to-json-schema-3.24.5.tgz#d1095440b147fb7c2093812a53c54df8d5df50a3" integrity sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g== -zod@^3.23.8, zod@^3.24.4: +zod-validation-error@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/zod-validation-error/-/zod-validation-error-4.0.1.tgz#a105723eb40299578a6a38cb86647068f6d005b1" + integrity sha512-F3rdaCOHs5ViJ5YTz5zzRtfkQdMdIeKudJAoxy7yB/2ZMEHw73lmCAcQw11r7++20MyGl4WV59EVh7A9rNAyog== + +zod@^3.23.8: version "3.24.4" resolved "https://registry.yarnpkg.com/zod/-/zod-3.24.4.tgz#e2e2cca5faaa012d76e527d0d36622e0a90c315f" integrity sha512-OdqJE9UDRPwWsrHjLN2F8bPxvwJBK22EHLWtanu0LSYr5YqzsaaW3RMgmjwr8Rypg5k+meEJdSPXJZXE/yqOMg== + +zod@^3.25.20: + version "3.25.76" + resolved "https://registry.yarnpkg.com/zod/-/zod-3.25.76.tgz#26841c3f6fd22a6a2760e7ccb719179768471e34" + integrity sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ== From 39a25bf20d4cafdca951e6aa0fa0bf74a00b378f Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 19 Aug 2025 03:07:42 +0000 Subject: [PATCH 79/91] chore(internal): refactor array check --- packages/mcp-server/src/headers.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/mcp-server/src/headers.ts b/packages/mcp-server/src/headers.ts index 17994ea..23c0b5e 100644 --- a/packages/mcp-server/src/headers.ts +++ b/packages/mcp-server/src/headers.ts @@ -6,6 +6,6 @@ import { IncomingMessage } from 'node:http'; export const parseAuthHeaders = (req: IncomingMessage): Partial => { const apiKey = - req.headers['x-api-key'] instanceof Array ? req.headers['x-api-key'][0] : req.headers['x-api-key']; + Array.isArray(req.headers['x-api-key']) ? req.headers['x-api-key'][0] : req.headers['x-api-key']; return { apiKey }; }; From e47261c644a962bc76c7ad5afb92ded38034098d Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 20 Aug 2025 06:32:58 +0000 Subject: [PATCH 80/91] chore(mcp): add cors to oauth metadata route --- packages/mcp-server/package.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/mcp-server/package.json b/packages/mcp-server/package.json index 2cd0ed0..19a51b0 100644 --- a/packages/mcp-server/package.json +++ b/packages/mcp-server/package.json @@ -30,6 +30,7 @@ "scan-documents": "file:../../dist/", "@cloudflare/cabidela": "^0.2.4", "@modelcontextprotocol/sdk": "^1.11.5", + "cors": "^2.8.5", "express": "^5.1.0", "jq-web": "https://github.com/stainless-api/jq-web/releases/download/v0.8.6/jq-web.tar.gz", "qs": "^6.14.0", @@ -42,6 +43,7 @@ "mcp-server": "dist/index.js" }, "devDependencies": { + "@types/cors": "^2.8.19", "@types/express": "^5.0.3", "@types/jest": "^29.4.0", "@types/yargs": "^17.0.8", From c36e7ab1ffe8f98f94603aa729b080bd16e034c4 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 20 Aug 2025 06:34:33 +0000 Subject: [PATCH 81/91] feat(mcp): add code execution tool --- package.json | 2 +- packages/mcp-server/package.json | 3 +- packages/mcp-server/src/code-tool-paths.cts | 3 + packages/mcp-server/src/code-tool-types.ts | 14 ++ packages/mcp-server/src/code-tool-worker.ts | 46 ++++++ packages/mcp-server/src/code-tool.ts | 146 ++++++++++++++++++++ packages/mcp-server/src/options.ts | 18 ++- packages/mcp-server/src/server.ts | 3 + yarn.lock | 7 +- 9 files changed, 230 insertions(+), 12 deletions(-) create mode 100644 packages/mcp-server/src/code-tool-paths.cts create mode 100644 packages/mcp-server/src/code-tool-types.ts create mode 100644 packages/mcp-server/src/code-tool-worker.ts create mode 100644 packages/mcp-server/src/code-tool.ts diff --git a/package.json b/package.json index a1efe2d..1a51d0b 100644 --- a/package.json +++ b/package.json @@ -44,7 +44,7 @@ "publint": "^0.2.12", "ts-jest": "^29.1.0", "ts-node": "^10.5.0", - "tsc-multi": "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.8/tsc-multi.tgz", + "tsc-multi": "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.9/tsc-multi.tgz", "tsconfig-paths": "^4.0.0", "typescript": "5.8.3", "typescript-eslint": "8.31.1" diff --git a/packages/mcp-server/package.json b/packages/mcp-server/package.json index 19a51b0..c280a07 100644 --- a/packages/mcp-server/package.json +++ b/packages/mcp-server/package.json @@ -30,6 +30,7 @@ "scan-documents": "file:../../dist/", "@cloudflare/cabidela": "^0.2.4", "@modelcontextprotocol/sdk": "^1.11.5", + "@valtown/deno-http-worker": "^0.0.21", "cors": "^2.8.5", "express": "^5.1.0", "jq-web": "https://github.com/stainless-api/jq-web/releases/download/v0.8.6/jq-web.tar.gz", @@ -57,7 +58,7 @@ "ts-jest": "^29.1.0", "ts-morph": "^19.0.0", "ts-node": "^10.5.0", - "tsc-multi": "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.8/tsc-multi.tgz", + "tsc-multi": "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.9/tsc-multi.tgz", "tsconfig-paths": "^4.0.0", "typescript": "5.8.3" }, diff --git a/packages/mcp-server/src/code-tool-paths.cts b/packages/mcp-server/src/code-tool-paths.cts new file mode 100644 index 0000000..15ce7f5 --- /dev/null +++ b/packages/mcp-server/src/code-tool-paths.cts @@ -0,0 +1,3 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export const workerPath = require.resolve('./code-tool-worker.mjs'); diff --git a/packages/mcp-server/src/code-tool-types.ts b/packages/mcp-server/src/code-tool-types.ts new file mode 100644 index 0000000..b4eb123 --- /dev/null +++ b/packages/mcp-server/src/code-tool-types.ts @@ -0,0 +1,14 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { type ClientOptions } from 'scan-documents/client'; + +export type WorkerInput = { + opts: ClientOptions; + code: string; +}; +export type WorkerSuccess = { + result: unknown | null; + logLines: string[]; + errLines: string[]; +}; +export type WorkerError = { message: string | undefined }; diff --git a/packages/mcp-server/src/code-tool-worker.ts b/packages/mcp-server/src/code-tool-worker.ts new file mode 100644 index 0000000..11e8851 --- /dev/null +++ b/packages/mcp-server/src/code-tool-worker.ts @@ -0,0 +1,46 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import util from 'node:util'; +import { WorkerInput, WorkerSuccess, WorkerError } from './code-tool-types'; +import { ScanDocuments } from 'scan-documents'; + +const fetch = async (req: Request): Promise => { + const { opts, code } = (await req.json()) as WorkerInput; + const client = new ScanDocuments({ + ...opts, + }); + + const logLines: string[] = []; + const errLines: string[] = []; + const console = { + log: (...args: unknown[]) => { + logLines.push(util.format(...args)); + }, + error: (...args: unknown[]) => { + errLines.push(util.format(...args)); + }, + }; + try { + let run_ = async (client: any) => {}; + eval(` + ${code} + run_ = run; + `); + const result = await run_(client); + return Response.json({ + result, + logLines, + errLines, + } satisfies WorkerSuccess); + } catch (e) { + const message = e instanceof Error ? e.message : undefined; + return Response.json( + { + message, + } satisfies WorkerError, + { status: 400, statusText: 'Code execution error' }, + ); + } +}; + +export default { fetch }; diff --git a/packages/mcp-server/src/code-tool.ts b/packages/mcp-server/src/code-tool.ts new file mode 100644 index 0000000..ef835ee --- /dev/null +++ b/packages/mcp-server/src/code-tool.ts @@ -0,0 +1,146 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { type ClientOptions } from 'scan-documents/client'; + +import { dirname } from 'node:path'; +import { pathToFileURL } from 'node:url'; +import ScanDocuments from 'scan-documents'; +import { Endpoint, ContentBlock, Metadata } from './tools/types'; + +import { Tool } from '@modelcontextprotocol/sdk/types.js'; + +import { newDenoHTTPWorker } from '@valtown/deno-http-worker'; +import { WorkerInput, WorkerError, WorkerSuccess } from './code-tool-types'; +import { workerPath } from './code-tool-paths.cjs'; + +/** + * A tool that runs code against a copy of the SDK. + * + * Instead of exposing every endpoint as it's own tool, which uses up too many tokens for LLMs to use at once, + * we expose a single tool that can be used to search for endpoints by name, resource, operation, or tag, and then + * a generic endpoint that can be used to invoke any endpoint with the provided arguments. + * + * @param endpoints - The endpoints to include in the list. + */ +export function codeTool(): Endpoint { + const metadata: Metadata = { resource: 'all', operation: 'write', tags: [] }; + const tool: Tool = { + name: 'execute', + description: + 'Runs Typescript code to interact with the API.\nYou are a skilled programmer writing code to interface with the service.\nDefine an async function named "run" that takes a single parameter of an initialized client, and it will be run.\nDo not initialize a client, but instead use the client that you are given as a parameter.\nYou will be returned anything that your function returns, plus the results of any console.log statements.\nIf any code triggers an error, the tool will return an error response, so you do not need to add error handling unless you want to output something more helpful than the raw error.\nIt is not necessary to add comments to code, unless by adding those comments you believe that you can generate better code.\nThis code will run in a container, and you will not be able to use fetch or otherwise interact with the network calls other than through the client you are given.\nAny variables you define won\'t live between successive uses of this call, so make sure to return or log any data you might need later.', + inputSchema: { type: 'object', properties: { code: { type: 'string' } } }, + }; + + const handler = async (client: ScanDocuments, args: unknown) => { + const baseURLHostname = new URL(client.baseURL).hostname; + const { code } = args as { code: string }; + + const worker = await newDenoHTTPWorker(pathToFileURL(workerPath), { + runFlags: [ + `--node-modules-dir=manual`, + `--allow-read=code-tool-worker.mjs,${workerPath.replace(/([\/\\]node_modules)[\/\\].+$/, '$1')}/`, + `--allow-net=${baseURLHostname}`, + // Allow environment variables because instantiating the client will try to read from them, + // even though they are not set. + '--allow-env', + ], + printOutput: true, + spawnOptions: { + cwd: dirname(workerPath), + }, + }); + + try { + const resp = await new Promise((resolve, reject) => { + worker.addEventListener('exit', (exitCode) => { + reject(new Error(`Worker exited with code ${exitCode}`)); + }); + + const opts: ClientOptions = { + baseURL: client.baseURL, + apiKey: client.apiKey, + defaultHeaders: { + 'X-Stainless-MCP': 'true', + }, + }; + + const req = worker.request( + 'http://localhost', + { + headers: { + 'content-type': 'application/json', + }, + method: 'POST', + }, + (resp) => { + const body: Uint8Array[] = []; + resp.on('error', (err) => { + reject(err); + }); + resp.on('data', (chunk) => { + body.push(chunk); + }); + resp.on('end', () => { + resolve( + new Response(Buffer.concat(body).toString(), { + status: resp.statusCode ?? 200, + headers: resp.headers as any, + }), + ); + }); + }, + ); + + const body = JSON.stringify({ + opts, + code, + } satisfies WorkerInput); + + req.write(body, (err) => { + if (err !== null && err !== undefined) { + reject(err); + } + }); + + req.end(); + }); + + if (resp.status === 200) { + const { result, logLines, errLines } = (await resp.json()) as WorkerSuccess; + const returnOutput: ContentBlock | null = + result === null ? null + : result === undefined ? null + : { + type: 'text', + text: typeof result === 'string' ? (result as string) : JSON.stringify(result), + }; + const logOutput: ContentBlock | null = + logLines.length === 0 ? + null + : { + type: 'text', + text: logLines.join('\n'), + }; + const errOutput: ContentBlock | null = + errLines.length === 0 ? + null + : { + type: 'text', + text: 'Error output:\n' + errLines.join('\n'), + }; + return { + content: [returnOutput, logOutput, errOutput].filter((block) => block !== null), + }; + } else { + const { message } = (await resp.json()) as WorkerError; + throw new Error(message); + } + } catch (e) { + throw e; + } finally { + worker.terminate(); + } + }; + + return { metadata, tool, handler }; +} diff --git a/packages/mcp-server/src/options.ts b/packages/mcp-server/src/options.ts index 0768d93..a174591 100644 --- a/packages/mcp-server/src/options.ts +++ b/packages/mcp-server/src/options.ts @@ -16,6 +16,7 @@ export type McpOptions = { client: ClientType | undefined; includeDynamicTools: boolean | undefined; includeAllTools: boolean | undefined; + includeCodeTools: boolean | undefined; filters: Filter[]; capabilities?: Partial; }; @@ -54,13 +55,13 @@ export function parseCLIOptions(): CLIOptions { .option('tools', { type: 'string', array: true, - choices: ['dynamic', 'all'], + choices: ['dynamic', 'all', 'code'], description: 'Use dynamic tools or all tools', }) .option('no-tools', { type: 'string', array: true, - choices: ['dynamic', 'all'], + choices: ['dynamic', 'all', 'code'], description: 'Do not use any dynamic or all tools', }) .option('tool', { @@ -251,11 +252,13 @@ export function parseCLIOptions(): CLIOptions { } } + const shouldIncludeToolType = (toolType: 'dynamic' | 'all' | 'code') => + explicitTools ? argv.tools?.includes(toolType) && !argv.noTools?.includes(toolType) : undefined; + const explicitTools = Boolean(argv.tools || argv.noTools); - const includeDynamicTools = - explicitTools ? argv.tools?.includes('dynamic') && !argv.noTools?.includes('dynamic') : undefined; - const includeAllTools = - explicitTools ? argv.tools?.includes('all') && !argv.noTools?.includes('all') : undefined; + const includeDynamicTools = shouldIncludeToolType('dynamic'); + const includeAllTools = shouldIncludeToolType('all'); + const includeCodeTools = shouldIncludeToolType('code'); const transport = argv.transport as 'stdio' | 'http'; @@ -264,6 +267,7 @@ export function parseCLIOptions(): CLIOptions { client: client && knownClients[client] ? client : undefined, includeDynamicTools, includeAllTools, + includeCodeTools, filters, capabilities: clientCapabilities, list: argv.list || false, @@ -385,6 +389,8 @@ export function parseQueryOptions(defaultOptions: McpOptions, query: unknown): M includeAllTools: defaultOptions.includeAllTools ?? (queryOptions.tools?.includes('all') && !queryOptions.no_tools?.includes('all')), + // Never include code tools on remote server. + includeCodeTools: undefined, filters, capabilities: clientCapabilities, }; diff --git a/packages/mcp-server/src/server.ts b/packages/mcp-server/src/server.ts index 7b7c0d9..5e81a9c 100644 --- a/packages/mcp-server/src/server.ts +++ b/packages/mcp-server/src/server.ts @@ -14,6 +14,7 @@ import { parseEmbeddedJSON, } from './compat'; import { dynamicTools } from './dynamic-tools'; +import { codeTool } from './code-tool'; import { McpOptions } from './options'; export { McpOptions } from './options'; @@ -116,6 +117,8 @@ export function selectTools(endpoints: Endpoint[], options: McpOptions): Endpoin includedTools = endpoints; } else if (options.includeDynamicTools) { includedTools = dynamicTools(endpoints); + } else if (options.includeCodeTools) { + includedTools = [codeTool()]; } else { includedTools = endpoints; } diff --git a/yarn.lock b/yarn.lock index fd164dc..8311caf 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3283,10 +3283,9 @@ ts-node@^10.5.0: v8-compile-cache-lib "^3.0.0" yn "3.1.1" -"tsc-multi@https://github.com/stainless-api/tsc-multi/releases/download/v1.1.8/tsc-multi.tgz": - version "1.1.8" - uid f544b359b8f05e607771ffacc280e58201476b04 - resolved "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.8/tsc-multi.tgz#f544b359b8f05e607771ffacc280e58201476b04" +"tsc-multi@https://github.com/stainless-api/tsc-multi/releases/download/v1.1.9/tsc-multi.tgz": + version "1.1.9" + resolved "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.9/tsc-multi.tgz#777f6f5d9e26bf0e94e5170990dd3a841d6707cd" dependencies: debug "^4.3.7" fast-glob "^3.3.2" From cb532ff281e968d46b3d5dd5710d36ac9bdd530e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 21 Aug 2025 05:45:55 +0000 Subject: [PATCH 82/91] chore(internal): make mcp-server publishing public by defaut --- packages/mcp-server/package.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/mcp-server/package.json b/packages/mcp-server/package.json index c280a07..f8a98cb 100644 --- a/packages/mcp-server/package.json +++ b/packages/mcp-server/package.json @@ -15,6 +15,9 @@ "license": "Apache-2.0", "packageManager": "yarn@1.22.22", "private": false, + "publishConfig": { + "access": "public" + }, "scripts": { "test": "jest", "build": "bash ./build", From 149e5145317a38b8acb37ec99948fc3aab8a2a2b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 21 Aug 2025 06:06:24 +0000 Subject: [PATCH 83/91] feat(mcp): add option to infer mcp client --- packages/mcp-server/src/compat.ts | 4 +- packages/mcp-server/src/http.ts | 7 +- packages/mcp-server/src/index.ts | 4 +- packages/mcp-server/src/options.ts | 46 +++++------- packages/mcp-server/src/server.ts | 85 ++++++++++++++--------- packages/mcp-server/src/stdio.ts | 7 +- packages/mcp-server/tests/options.test.ts | 25 +------ 7 files changed, 78 insertions(+), 100 deletions(-) diff --git a/packages/mcp-server/src/compat.ts b/packages/mcp-server/src/compat.ts index 1df7a7a..f84053c 100644 --- a/packages/mcp-server/src/compat.ts +++ b/packages/mcp-server/src/compat.ts @@ -20,13 +20,13 @@ export const defaultClientCapabilities: ClientCapabilities = { toolNameLength: undefined, }; -export const ClientType = z.enum(['openai-agents', 'claude', 'claude-code', 'cursor']); +export const ClientType = z.enum(['openai-agents', 'claude', 'claude-code', 'cursor', 'infer']); export type ClientType = z.infer; // Client presets for compatibility // Note that these could change over time as models get better, so this is // a best effort. -export const knownClients: Record = { +export const knownClients: Record, ClientCapabilities> = { 'openai-agents': { topLevelUnions: false, validJson: true, diff --git a/packages/mcp-server/src/http.ts b/packages/mcp-server/src/http.ts index ca6d3d2..c11185b 100644 --- a/packages/mcp-server/src/http.ts +++ b/packages/mcp-server/src/http.ts @@ -8,7 +8,6 @@ import { fromError } from 'zod-validation-error/v3'; import { McpOptions, parseQueryOptions } from './options'; import { initMcpServer, newMcpServer } from './server'; import { parseAuthHeaders } from './headers'; -import { Endpoint } from './tools'; const newServer = ( defaultMcpOptions: McpOptions, @@ -101,11 +100,7 @@ export const streamableHTTPApp = (options: McpOptions): express.Express => { return app; }; -export const launchStreamableHTTPServer = async ( - options: McpOptions, - endpoints: Endpoint[], - port: number | string | undefined, -) => { +export const launchStreamableHTTPServer = async (options: McpOptions, port: number | string | undefined) => { const app = streamableHTTPApp(options); const server = app.listen(port); const address = server.address(); diff --git a/packages/mcp-server/src/index.ts b/packages/mcp-server/src/index.ts index 05b2ba6..c450e4b 100644 --- a/packages/mcp-server/src/index.ts +++ b/packages/mcp-server/src/index.ts @@ -23,10 +23,10 @@ async function main() { switch (options.transport) { case 'stdio': - await launchStdioServer(options, selectedTools); + await launchStdioServer(options); break; case 'http': - await launchStreamableHTTPServer(options, selectedTools, options.port ?? options.socket); + await launchStreamableHTTPServer(options, options.port ?? options.socket); break; } } diff --git a/packages/mcp-server/src/options.ts b/packages/mcp-server/src/options.ts index a174591..9eb00b4 100644 --- a/packages/mcp-server/src/options.ts +++ b/packages/mcp-server/src/options.ts @@ -13,12 +13,12 @@ export type CLIOptions = McpOptions & { }; export type McpOptions = { - client: ClientType | undefined; - includeDynamicTools: boolean | undefined; - includeAllTools: boolean | undefined; - includeCodeTools: boolean | undefined; - filters: Filter[]; - capabilities?: Partial; + client?: ClientType | undefined; + includeDynamicTools?: boolean | undefined; + includeAllTools?: boolean | undefined; + includeCodeTools?: boolean | undefined; + filters?: Filter[] | undefined; + capabilities?: Partial | undefined; }; const CAPABILITY_CHOICES = [ @@ -204,14 +204,7 @@ export function parseCLIOptions(): CLIOptions { } // Parse client capabilities - const clientCapabilities: ClientCapabilities = { - topLevelUnions: true, - validJson: true, - refs: true, - unions: true, - formats: true, - toolNameLength: undefined, - }; + const clientCapabilities: Partial = {}; // Apply individual capability overrides if (Array.isArray(argv.capability)) { @@ -264,7 +257,7 @@ export function parseCLIOptions(): CLIOptions { const client = argv.client as ClientType; return { - client: client && knownClients[client] ? client : undefined, + client: client && client !== 'infer' && knownClients[client] ? client : undefined, includeDynamicTools, includeAllTools, includeCodeTools, @@ -310,7 +303,7 @@ export function parseQueryOptions(defaultOptions: McpOptions, query: unknown): M const queryObject = typeof query === 'string' ? qs.parse(query) : query; const queryOptions = QueryOptions.parse(queryObject); - const filters: Filter[] = [...defaultOptions.filters]; + const filters: Filter[] = [...(defaultOptions.filters ?? [])]; for (const resource of queryOptions.resource || []) { filters.push({ type: 'resource', op: 'include', value: resource }); @@ -338,15 +331,7 @@ export function parseQueryOptions(defaultOptions: McpOptions, query: unknown): M } // Parse client capabilities - const clientCapabilities: ClientCapabilities = { - topLevelUnions: true, - validJson: true, - refs: true, - unions: true, - formats: true, - toolNameLength: undefined, - ...defaultOptions.capabilities, - }; + const clientCapabilities: Partial = { ...defaultOptions.capabilities }; for (const cap of queryOptions.capability || []) { const parsed = parseCapabilityValue(cap); @@ -384,12 +369,13 @@ export function parseQueryOptions(defaultOptions: McpOptions, query: unknown): M return { client: queryOptions.client ?? defaultOptions.client, includeDynamicTools: - defaultOptions.includeDynamicTools ?? - (queryOptions.tools?.includes('dynamic') && !queryOptions.no_tools?.includes('dynamic')), + defaultOptions.includeDynamicTools === false ? + false + : queryOptions.tools?.includes('dynamic') && !queryOptions.no_tools?.includes('dynamic'), includeAllTools: - defaultOptions.includeAllTools ?? - (queryOptions.tools?.includes('all') && !queryOptions.no_tools?.includes('all')), - // Never include code tools on remote server. + defaultOptions.includeAllTools === false ? + false + : queryOptions.tools?.includes('all') && !queryOptions.no_tools?.includes('all'), includeCodeTools: undefined, filters, capabilities: clientCapabilities, diff --git a/packages/mcp-server/src/server.ts b/packages/mcp-server/src/server.ts index 5e81a9c..08c65da 100644 --- a/packages/mcp-server/src/server.ts +++ b/packages/mcp-server/src/server.ts @@ -3,7 +3,12 @@ import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import { Endpoint, endpoints, HandlerFunction, query } from './tools'; -import { CallToolRequestSchema, ListToolsRequestSchema, Tool } from '@modelcontextprotocol/sdk/types.js'; +import { + CallToolRequestSchema, + Implementation, + ListToolsRequestSchema, + Tool, +} from '@modelcontextprotocol/sdk/types.js'; import { ClientOptions } from 'scan-documents'; import ScanDocuments from 'scan-documents'; import { @@ -41,29 +46,29 @@ export const server = newMcpServer(); */ export function initMcpServer(params: { server: Server | McpServer; - clientOptions: ClientOptions; - mcpOptions: McpOptions; - endpoints?: { tool: Tool; handler: HandlerFunction }[]; -}) { - const transformedEndpoints = selectTools(endpoints, params.mcpOptions); - const client = new ScanDocuments(params.clientOptions); - const capabilities = { - ...defaultClientCapabilities, - ...(params.mcpOptions.client ? knownClients[params.mcpOptions.client] : params.mcpOptions.capabilities), - }; - init({ server: params.server, client, endpoints: transformedEndpoints, capabilities }); -} - -export function init(params: { - server: Server | McpServer; - client?: ScanDocuments; - endpoints?: { tool: Tool; handler: HandlerFunction }[]; - capabilities?: Partial; + clientOptions?: ClientOptions; + mcpOptions?: McpOptions; }) { const server = params.server instanceof McpServer ? params.server.server : params.server; - const providedEndpoints = params.endpoints || endpoints; - - const endpointMap = Object.fromEntries(providedEndpoints.map((endpoint) => [endpoint.tool.name, endpoint])); + const mcpOptions = params.mcpOptions ?? {}; + + let providedEndpoints: Endpoint[] | null = null; + let endpointMap: Record | null = null; + + const initTools = (implementation?: Implementation) => { + if (implementation && (!mcpOptions.client || mcpOptions.client === 'infer')) { + mcpOptions.client = + implementation.name.toLowerCase().includes('claude') ? 'claude' + : implementation.name.toLowerCase().includes('cursor') ? 'cursor' + : undefined; + mcpOptions.capabilities = { + ...(mcpOptions.client && knownClients[mcpOptions.client]), + ...mcpOptions.capabilities, + }; + } + providedEndpoints = selectTools(endpoints, mcpOptions); + endpointMap = Object.fromEntries(providedEndpoints.map((endpoint) => [endpoint.tool.name, endpoint])); + }; const logAtLevel = (level: 'debug' | 'info' | 'warning' | 'error') => @@ -80,51 +85,63 @@ export function init(params: { error: logAtLevel('error'), }; - const client = - params.client || new ScanDocuments({ defaultHeaders: { 'X-Stainless-MCP': 'true' }, logger: logger }); + const client = new ScanDocuments({ + logger, + ...params.clientOptions, + defaultHeaders: { + ...params.clientOptions?.defaultHeaders, + 'X-Stainless-MCP': 'true', + }, + }); server.setRequestHandler(ListToolsRequestSchema, async () => { + if (providedEndpoints === null) { + initTools(server.getClientVersion()); + } return { - tools: providedEndpoints.map((endpoint) => endpoint.tool), + tools: providedEndpoints!.map((endpoint) => endpoint.tool), }; }); server.setRequestHandler(CallToolRequestSchema, async (request) => { + if (endpointMap === null) { + initTools(server.getClientVersion()); + } const { name, arguments: args } = request.params; - const endpoint = endpointMap[name]; + const endpoint = endpointMap![name]; if (!endpoint) { throw new Error(`Unknown tool: ${name}`); } - return executeHandler(endpoint.tool, endpoint.handler, client, args, params.capabilities); + return executeHandler(endpoint.tool, endpoint.handler, client, args, mcpOptions.capabilities); }); } /** * Selects the tools to include in the MCP Server based on the provided options. */ -export function selectTools(endpoints: Endpoint[], options: McpOptions): Endpoint[] { - const filteredEndpoints = query(options.filters, endpoints); +export function selectTools(endpoints: Endpoint[], options?: McpOptions): Endpoint[] { + const filteredEndpoints = query(options?.filters ?? [], endpoints); let includedTools = filteredEndpoints; if (includedTools.length > 0) { - if (options.includeDynamicTools) { + if (options?.includeDynamicTools) { includedTools = dynamicTools(includedTools); } } else { - if (options.includeAllTools) { + if (options?.includeAllTools) { includedTools = endpoints; - } else if (options.includeDynamicTools) { + } else if (options?.includeDynamicTools) { includedTools = dynamicTools(endpoints); - } else if (options.includeCodeTools) { + } else if (options?.includeCodeTools) { includedTools = [codeTool()]; } else { includedTools = endpoints; } } - const capabilities = { ...defaultClientCapabilities, ...options.capabilities }; + const capabilities = { ...defaultClientCapabilities, ...options?.capabilities }; return applyCompatibilityTransformations(includedTools, capabilities); } diff --git a/packages/mcp-server/src/stdio.ts b/packages/mcp-server/src/stdio.ts index b269163..d902a5b 100644 --- a/packages/mcp-server/src/stdio.ts +++ b/packages/mcp-server/src/stdio.ts @@ -1,12 +1,11 @@ import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; -import { init, newMcpServer } from './server'; -import { Endpoint } from './tools'; +import { initMcpServer, newMcpServer } from './server'; import { McpOptions } from './options'; -export const launchStdioServer = async (options: McpOptions, endpoints: Endpoint[]) => { +export const launchStdioServer = async (options: McpOptions) => { const server = newMcpServer(); - init({ server, endpoints }); + initMcpServer({ server, mcpOptions: options }); const transport = new StdioServerTransport(); await server.connect(transport); diff --git a/packages/mcp-server/tests/options.test.ts b/packages/mcp-server/tests/options.test.ts index 08ea1f1..24604b8 100644 --- a/packages/mcp-server/tests/options.test.ts +++ b/packages/mcp-server/tests/options.test.ts @@ -29,15 +29,7 @@ describe('parseCLIOptions', () => { { type: 'operation', op: 'include', value: 'read' }, ] as Filter[]); - // Default client capabilities - expect(result.capabilities).toEqual({ - topLevelUnions: true, - validJson: true, - refs: true, - unions: true, - formats: true, - toolNameLength: undefined, - }); + expect(result.capabilities).toEqual({}); expect(result.list).toBe(false); @@ -61,14 +53,7 @@ describe('parseCLIOptions', () => { { type: 'operation', op: 'exclude', value: 'write' }, ] as Filter[]); - expect(result.capabilities).toEqual({ - topLevelUnions: true, - validJson: true, - refs: true, - unions: true, - formats: true, - toolNameLength: undefined, - }); + expect(result.capabilities).toEqual({}); cleanup(); }); @@ -99,7 +84,6 @@ describe('parseCLIOptions', () => { validJson: true, refs: true, unions: true, - formats: true, toolNameLength: 40, }); @@ -150,10 +134,7 @@ describe('parseCLIOptions', () => { expect(result.capabilities).toEqual({ topLevelUnions: true, validJson: true, - refs: true, unions: true, - formats: true, - toolNameLength: undefined, }); cleanup(); @@ -316,7 +297,7 @@ describe('parseQueryOptions', () => { ]); expect(result.client).toBe('cursor'); - expect(result.includeDynamicTools).toBe(true); + expect(result.includeDynamicTools).toBe(undefined); }); it('should override client from default options', () => { From 261f3f5cef6e12b4d435264bc11ce5cc52f6ec6b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 22 Aug 2025 06:43:33 +0000 Subject: [PATCH 84/91] chore(mcp): update package.json --- packages/mcp-server/package.json | 1 + packages/mcp-server/src/headers.ts | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/mcp-server/package.json b/packages/mcp-server/package.json index f8a98cb..af8d75f 100644 --- a/packages/mcp-server/package.json +++ b/packages/mcp-server/package.json @@ -50,6 +50,7 @@ "@types/cors": "^2.8.19", "@types/express": "^5.0.3", "@types/jest": "^29.4.0", + "@types/qs": "^6.14.0", "@types/yargs": "^17.0.8", "@typescript-eslint/eslint-plugin": "8.31.1", "@typescript-eslint/parser": "8.31.1", diff --git a/packages/mcp-server/src/headers.ts b/packages/mcp-server/src/headers.ts index 23c0b5e..dd99503 100644 --- a/packages/mcp-server/src/headers.ts +++ b/packages/mcp-server/src/headers.ts @@ -1,8 +1,7 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { type ClientOptions } from 'scan-documents/client'; - import { IncomingMessage } from 'node:http'; +import { ClientOptions } from 'scan-documents'; export const parseAuthHeaders = (req: IncomingMessage): Partial => { const apiKey = From 079839c4089e8cf828d49a36339dc8764e1b6e71 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 22 Aug 2025 06:58:05 +0000 Subject: [PATCH 85/91] chore(mcp): update types --- packages/mcp-server/src/code-tool-types.ts | 2 +- packages/mcp-server/src/code-tool.ts | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/mcp-server/src/code-tool-types.ts b/packages/mcp-server/src/code-tool-types.ts index b4eb123..409f492 100644 --- a/packages/mcp-server/src/code-tool-types.ts +++ b/packages/mcp-server/src/code-tool-types.ts @@ -1,6 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { type ClientOptions } from 'scan-documents/client'; +import { ClientOptions } from 'scan-documents'; export type WorkerInput = { opts: ClientOptions; diff --git a/packages/mcp-server/src/code-tool.ts b/packages/mcp-server/src/code-tool.ts index ef835ee..03452d4 100644 --- a/packages/mcp-server/src/code-tool.ts +++ b/packages/mcp-server/src/code-tool.ts @@ -1,10 +1,8 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { type ClientOptions } from 'scan-documents/client'; - import { dirname } from 'node:path'; import { pathToFileURL } from 'node:url'; -import ScanDocuments from 'scan-documents'; +import ScanDocuments, { ClientOptions } from 'scan-documents'; import { Endpoint, ContentBlock, Metadata } from './tools/types'; import { Tool } from '@modelcontextprotocol/sdk/types.js'; From 52c22269924c2992a427ce0136bf1f9effd4da8b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 22 Aug 2025 06:59:57 +0000 Subject: [PATCH 86/91] chore: add package to package.json --- package.json | 1 + scripts/bootstrap | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 1a51d0b..bf595ba 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "ts-node": "^10.5.0", "tsc-multi": "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.9/tsc-multi.tgz", "tsconfig-paths": "^4.0.0", + "tslib": "^2.8.1", "typescript": "5.8.3", "typescript-eslint": "8.31.1" }, diff --git a/scripts/bootstrap b/scripts/bootstrap index 0af58e2..062a034 100755 --- a/scripts/bootstrap +++ b/scripts/bootstrap @@ -15,4 +15,4 @@ echo "==> Installing Node dependencies…" PACKAGE_MANAGER=$(command -v yarn >/dev/null 2>&1 && echo "yarn" || echo "npm") -$PACKAGE_MANAGER install +$PACKAGE_MANAGER install "$@" From 3554f3cab5ce7969889c889bb833e8aa45740159 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 22 Aug 2025 07:01:47 +0000 Subject: [PATCH 87/91] chore(internal): codegen related update --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0e2457d..dfe5d29 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,7 +24,7 @@ jobs: - name: Set up Node uses: actions/setup-node@v4 with: - node-version: '20' + node-version: '22' - name: Bootstrap run: ./scripts/bootstrap @@ -46,7 +46,7 @@ jobs: - name: Set up Node uses: actions/setup-node@v4 with: - node-version: '20' + node-version: '22' - name: Bootstrap run: ./scripts/bootstrap From b110292d90aa445e9d73dd7cfa77d2bd57e46aa9 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 22 Aug 2025 07:05:05 +0000 Subject: [PATCH 88/91] chore(client): qualify global Blob --- src/client.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client.ts b/src/client.ts index bb7e9b6..bcadfe9 100644 --- a/src/client.ts +++ b/src/client.ts @@ -710,7 +710,7 @@ export class ScanDocuments { // Preserve legacy string encoding behavior for now headers.values.has('content-type')) || // `Blob` is superset of `File` - body instanceof Blob || + ((globalThis as any).Blob && body instanceof (globalThis as any).Blob) || // `FormData` -> `multipart/form-data` body instanceof FormData || // `URLSearchParams` -> `application/x-www-form-urlencoded` From 2ace29730fa8c3b74531c0945e955b1339fafc6c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 23 Aug 2025 05:24:31 +0000 Subject: [PATCH 89/91] chore: update CI script --- .github/workflows/ci.yml | 9 +++++++++ scripts/utils/upload-artifact.sh | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dfe5d29..3058099 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -68,6 +68,15 @@ jobs: AUTH: ${{ steps.github-oidc.outputs.github_token }} SHA: ${{ github.sha }} run: ./scripts/utils/upload-artifact.sh + + - name: Upload MCP Server tarball + if: github.repository == 'stainless-sdks/scan-documents-typescript' + env: + URL: https://pkg.stainless.com/s?subpackage=mcp-server + AUTH: ${{ steps.github-oidc.outputs.github_token }} + SHA: ${{ github.sha }} + BUILD_PATH: packages/mcp-server/dist + run: ./scripts/utils/upload-artifact.sh test: timeout-minutes: 10 name: test diff --git a/scripts/utils/upload-artifact.sh b/scripts/utils/upload-artifact.sh index d89492a..a6a7b81 100755 --- a/scripts/utils/upload-artifact.sh +++ b/scripts/utils/upload-artifact.sh @@ -12,7 +12,7 @@ if [[ "$SIGNED_URL" == "null" ]]; then exit 1 fi -UPLOAD_RESPONSE=$(tar -cz dist | curl -v -X PUT \ +UPLOAD_RESPONSE=$(tar -cz "${BUILD_PATH:-dist}" | curl -v -X PUT \ -H "Content-Type: application/gzip" \ --data-binary @- "$SIGNED_URL" 2>&1) From 5560f78a373d434a2b1a86f57fd14da284581bc0 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sun, 24 Aug 2025 02:29:19 +0000 Subject: [PATCH 90/91] chore(internal): codegen related update --- packages/mcp-server/src/options.ts | 20 ++++++++++++-------- packages/mcp-server/tests/options.test.ts | 2 +- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/packages/mcp-server/src/options.ts b/packages/mcp-server/src/options.ts index 9eb00b4..2100cf5 100644 --- a/packages/mcp-server/src/options.ts +++ b/packages/mcp-server/src/options.ts @@ -366,16 +366,20 @@ export function parseQueryOptions(defaultOptions: McpOptions, query: unknown): M } } + let dynamicTools: boolean | undefined = + queryOptions.no_tools && !queryOptions.no_tools?.includes('dynamic') ? false + : queryOptions.tools?.includes('dynamic') ? true + : defaultOptions.includeDynamicTools; + + let allTools: boolean | undefined = + queryOptions.no_tools && !queryOptions.no_tools?.includes('all') ? false + : queryOptions.tools?.includes('all') ? true + : defaultOptions.includeAllTools; + return { client: queryOptions.client ?? defaultOptions.client, - includeDynamicTools: - defaultOptions.includeDynamicTools === false ? - false - : queryOptions.tools?.includes('dynamic') && !queryOptions.no_tools?.includes('dynamic'), - includeAllTools: - defaultOptions.includeAllTools === false ? - false - : queryOptions.tools?.includes('all') && !queryOptions.no_tools?.includes('all'), + includeDynamicTools: dynamicTools, + includeAllTools: allTools, includeCodeTools: undefined, filters, capabilities: clientCapabilities, diff --git a/packages/mcp-server/tests/options.test.ts b/packages/mcp-server/tests/options.test.ts index 24604b8..a8a5b81 100644 --- a/packages/mcp-server/tests/options.test.ts +++ b/packages/mcp-server/tests/options.test.ts @@ -297,7 +297,7 @@ describe('parseQueryOptions', () => { ]); expect(result.client).toBe('cursor'); - expect(result.includeDynamicTools).toBe(undefined); + expect(result.includeDynamicTools).toBe(true); }); it('should override client from default options', () => { From a6cd56de58f18c4ff52ea46999ed424798b0ccd1 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sun, 24 Aug 2025 02:29:54 +0000 Subject: [PATCH 91/91] release: 0.1.0-alpha.6 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 62 +++++++++++++++++++++++++++++++ package.json | 2 +- packages/mcp-server/package.json | 2 +- packages/mcp-server/src/server.ts | 2 +- src/version.ts | 2 +- 6 files changed, 67 insertions(+), 5 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index 12342be..5375ff4 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.1.0-alpha.5" + ".": "0.1.0-alpha.6" } diff --git a/CHANGELOG.md b/CHANGELOG.md index 14f66d4..a8d34f2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,67 @@ # Changelog +## 0.1.0-alpha.6 (2025-08-24) + +Full Changelog: [v0.1.0-alpha.5...v0.1.0-alpha.6](https://github.com/Scan-Documents/node-sdk/compare/v0.1.0-alpha.5...v0.1.0-alpha.6) + +### Features + +* **api:** update via SDK Studio ([29066c7](https://github.com/Scan-Documents/node-sdk/commit/29066c78a803d4eb260385bdf2a3e7748390b91d)) +* **mcp:** add code execution tool ([c36e7ab](https://github.com/Scan-Documents/node-sdk/commit/c36e7ab1ffe8f98f94603aa729b080bd16e034c4)) +* **mcp:** add logging when environment variable is set ([57fc795](https://github.com/Scan-Documents/node-sdk/commit/57fc7959d83c30d25152a60aeb8895df38ab15b8)) +* **mcp:** add option to infer mcp client ([149e514](https://github.com/Scan-Documents/node-sdk/commit/149e5145317a38b8acb37ec99948fc3aab8a2a2b)) +* **mcp:** add unix socket option for remote MCP ([72982bc](https://github.com/Scan-Documents/node-sdk/commit/72982bc112a6a5725956354b361944069cf92faa)) +* **mcp:** fallback for void-typed methods ([965b606](https://github.com/Scan-Documents/node-sdk/commit/965b6064ff025b992e21c9fd54edbe6963d27b6b)) +* **mcp:** parse query string as mcp client options in mcp server ([a72cd42](https://github.com/Scan-Documents/node-sdk/commit/a72cd4273cb2efc360656de84e17c94d2ba21c25)) +* **mcp:** remote server with passthru auth ([05f1022](https://github.com/Scan-Documents/node-sdk/commit/05f1022cf2d8897c5ca52bdac865fea951dabc39)) +* **mcp:** support filtering tool results by a jq expression ([436421e](https://github.com/Scan-Documents/node-sdk/commit/436421e66b382295d19149478a5cabb21bce12a6)) + + +### Bug Fixes + +* **ci:** release-doctor — report correct token name ([2430747](https://github.com/Scan-Documents/node-sdk/commit/2430747fe786df1a9e237b884c59082cfc21a2bf)) +* **client:** get fetchOptions type more reliably ([0a17458](https://github.com/Scan-Documents/node-sdk/commit/0a17458ddfe37d5b3e5c10f7e257fad3e2d08129)) +* **mcp:** avoid sending `jq_filter` to base API ([11b40cc](https://github.com/Scan-Documents/node-sdk/commit/11b40cca569792c127c204a6ca9c39e688b182be)) +* **mcp:** fix tool description of jq_filter ([33effa6](https://github.com/Scan-Documents/node-sdk/commit/33effa6ccb54e2da65a9aaad00bcbb7070e2bdd0)) +* **mcp:** generate additionalProperties=true for map schemas to avoid validation issues ([488ee1c](https://github.com/Scan-Documents/node-sdk/commit/488ee1c68366d5253d75565838c2c3447af525b1)) +* **mcp:** include required section for top-level properties and support naming transformations ([f7827a6](https://github.com/Scan-Documents/node-sdk/commit/f7827a6390ec0922cdc039344f47774cf588da14)) +* **mcp:** relax input type for asTextContextResult ([7f50ae3](https://github.com/Scan-Documents/node-sdk/commit/7f50ae35b174c4e7863bfc71c71ce70f71893ef7)) +* **mcp:** reverse validJson capability option and limit scope ([41bd333](https://github.com/Scan-Documents/node-sdk/commit/41bd333e563e4b23100f1f239928aa8c60fc223c)) +* **mcp:** support jq filtering on cloudflare workers ([d2bee12](https://github.com/Scan-Documents/node-sdk/commit/d2bee126b3794e12e7a66fd1df7600a89c7adf7a)) + + +### Chores + +* add docs to RequestOptions type ([26a2df1](https://github.com/Scan-Documents/node-sdk/commit/26a2df16f3133c6f3ebfa06a906ccbdb667b763c)) +* add package to package.json ([52c2226](https://github.com/Scan-Documents/node-sdk/commit/52c22269924c2992a427ce0136bf1f9effd4da8b)) +* **ci:** only run for pushes and fork pull requests ([fedf819](https://github.com/Scan-Documents/node-sdk/commit/fedf819df77819d08582e26bf2d768a0971684d0)) +* **client:** improve path param validation ([00bb123](https://github.com/Scan-Documents/node-sdk/commit/00bb1237344ad7b4d3cafb5ee3f8015033f581ad)) +* **client:** qualify global Blob ([b110292](https://github.com/Scan-Documents/node-sdk/commit/b110292d90aa445e9d73dd7cfa77d2bd57e46aa9)) +* **deps:** update dependency @types/node to v20.17.58 ([b435ab1](https://github.com/Scan-Documents/node-sdk/commit/b435ab1ef8e26e20a35842579846c87cd20ff4be)) +* **internal:** codegen related update ([5560f78](https://github.com/Scan-Documents/node-sdk/commit/5560f78a373d434a2b1a86f57fd14da284581bc0)) +* **internal:** codegen related update ([3554f3c](https://github.com/Scan-Documents/node-sdk/commit/3554f3cab5ce7969889c889bb833e8aa45740159)) +* **internal:** codegen related update ([4d9ab35](https://github.com/Scan-Documents/node-sdk/commit/4d9ab3563cfe93b7a61097a484e9f37f7604c5b7)) +* **internal:** codegen related update ([b47458d](https://github.com/Scan-Documents/node-sdk/commit/b47458d7c6269e4acbfc6fb4b469597581633e49)) +* **internal:** formatting change ([5a0343c](https://github.com/Scan-Documents/node-sdk/commit/5a0343c3751c96f3637abfd0ea84df271abf70a2)) +* **internal:** make mcp-server publishing public by defaut ([cb532ff](https://github.com/Scan-Documents/node-sdk/commit/cb532ff281e968d46b3d5dd5710d36ac9bdd530e)) +* **internal:** move publish config ([1947212](https://github.com/Scan-Documents/node-sdk/commit/1947212b285dd090527c98fb607308003036e1e3)) +* **internal:** refactor array check ([39a25bf](https://github.com/Scan-Documents/node-sdk/commit/39a25bf20d4cafdca951e6aa0fa0bf74a00b378f)) +* **internal:** remove redundant imports config ([cfe049c](https://github.com/Scan-Documents/node-sdk/commit/cfe049c407230ed71a4216f893cedb1c85ba856e)) +* **internal:** update comment in script ([3be780c](https://github.com/Scan-Documents/node-sdk/commit/3be780cb1d9bc7136a79a2f130617a42bd38b081)) +* make some internal functions async ([064caed](https://github.com/Scan-Documents/node-sdk/commit/064caed6799b56c06d441e02319f31ca79f0549f)) +* **mcp:** add cors to oauth metadata route ([e47261c](https://github.com/Scan-Documents/node-sdk/commit/e47261c644a962bc76c7ad5afb92ded38034098d)) +* **mcp:** document remote server in README.md ([64f8b3a](https://github.com/Scan-Documents/node-sdk/commit/64f8b3a076b881b43878aa2e78c2942a6b53d98d)) +* **mcp:** formatting ([32923a2](https://github.com/Scan-Documents/node-sdk/commit/32923a200bbe8c6ba2658428be044bd14e5f09cb)) +* **mcp:** minor cleanup of types and package.json ([938a40b](https://github.com/Scan-Documents/node-sdk/commit/938a40bc3dc1b8f4cacdea781c23dea0680ac1eb)) +* **mcp:** refactor streamable http transport ([8a955ea](https://github.com/Scan-Documents/node-sdk/commit/8a955eaa7bb01a0a85817567cd0000a15cdca487)) +* **mcp:** rework imports in tools ([df24a2f](https://github.com/Scan-Documents/node-sdk/commit/df24a2f821d16e2ef006bf6715be5d87b1179a83)) +* **mcp:** update package.json ([261f3f5](https://github.com/Scan-Documents/node-sdk/commit/261f3f5cef6e12b4d435264bc11ce5cc52f6ec6b)) +* **mcp:** update README ([b821690](https://github.com/Scan-Documents/node-sdk/commit/b821690f1b0a2494dcb6b2ab0643a212b4a040dc)) +* **mcp:** update types ([079839c](https://github.com/Scan-Documents/node-sdk/commit/079839c4089e8cf828d49a36339dc8764e1b6e71)) +* **ts:** reorder package.json imports ([596fc4f](https://github.com/Scan-Documents/node-sdk/commit/596fc4f6d1323ceeecf8eef62cc165d5430f9069)) +* update @stainless-api/prism-cli to v5.15.0 ([b609b33](https://github.com/Scan-Documents/node-sdk/commit/b609b338d3f8db485a3ede5f4fe920db21c79149)) +* update CI script ([2ace297](https://github.com/Scan-Documents/node-sdk/commit/2ace29730fa8c3b74531c0945e955b1339fafc6c)) + ## 0.1.0-alpha.5 (2025-06-24) Full Changelog: [v0.1.0-alpha.4...v0.1.0-alpha.5](https://github.com/Scan-Documents/node-sdk/compare/v0.1.0-alpha.4...v0.1.0-alpha.5) diff --git a/package.json b/package.json index bf595ba..d6fc9b6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "scan-documents", - "version": "0.1.0-alpha.5", + "version": "0.1.0-alpha.6", "description": "The official TypeScript library for the Scan Documents API", "author": "Scan Documents ", "types": "dist/index.d.ts", diff --git a/packages/mcp-server/package.json b/packages/mcp-server/package.json index af8d75f..24b51c2 100644 --- a/packages/mcp-server/package.json +++ b/packages/mcp-server/package.json @@ -1,6 +1,6 @@ { "name": "scan-documents-mcp", - "version": "0.1.0-alpha.5", + "version": "0.1.0-alpha.6", "description": "The official MCP Server for the Scan Documents API", "author": "Scan Documents ", "types": "dist/index.d.ts", diff --git a/packages/mcp-server/src/server.ts b/packages/mcp-server/src/server.ts index 08c65da..4a33637 100644 --- a/packages/mcp-server/src/server.ts +++ b/packages/mcp-server/src/server.ts @@ -32,7 +32,7 @@ export const newMcpServer = () => new McpServer( { name: 'scan_documents_api', - version: '0.1.0-alpha.5', + version: '0.1.0-alpha.6', }, { capabilities: { tools: {}, logging: {} } }, ); diff --git a/src/version.ts b/src/version.ts index 66c10e6..9b7cfeb 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1 +1 @@ -export const VERSION = '0.1.0-alpha.5'; // x-release-please-version +export const VERSION = '0.1.0-alpha.6'; // x-release-please-version