diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 00000000..12ff1e64 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,59 @@ +# Dependencies +node_modules/ +**/node_modules/ + +# Build outputs +dist/ +**/dist/ + +# Git +.git/ +.gitignore + +# CI/CD +.github/ +.gitlab-ci.yml +.travis.yml + +# IDE +.vscode/ +.idea/ +*.swp +*.swo +*~ + +# OS +.DS_Store +Thumbs.db + +# Testing +test/ +tests/ +__tests__/ +*.test.js +*.spec.js +coverage/ +.nyc_output/ + +# Logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# Environment +.env +.env.* + +# Temporary files +*.tmp +*.temp +.cache/ + +# Examples and scripts +examples/ +bin/ + +# Other packages (we only need mcp-server) +packages/*/ +!packages/mcp-server/ diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5eba6aef..d603b8b0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,12 +1,14 @@ name: CI on: push: - branches-ignore: - - 'generated' - - 'codegen/**' - - 'integrated/**' - - 'stl-preview-head/**' - - 'stl-preview-base/**' + branches: + - '**' + - '!integrated/**' + - '!stl-preview-head/**' + - '!stl-preview-base/**' + - '!generated' + - '!codegen/**' + - 'codegen/stl/**' pull_request: branches-ignore: - 'stl-preview-head/**' @@ -17,14 +19,14 @@ jobs: timeout-minutes: 10 name: lint runs-on: ${{ github.repository == 'stainless-sdks/beagle-typescript' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} - if: github.event_name == 'push' || github.event.pull_request.head.repo.fork + if: (github.event_name == 'push' || github.event.pull_request.head.repo.fork) && (github.event_name != 'push' || github.event.head_commit.message != 'codegen metadata') steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Set up Node - uses: actions/setup-node@v4 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: - node-version: '20' + node-version: '22' - name: Bootstrap run: ./scripts/bootstrap @@ -36,17 +38,17 @@ jobs: timeout-minutes: 5 name: build runs-on: ${{ github.repository == 'stainless-sdks/beagle-typescript' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} - if: github.event_name == 'push' || github.event.pull_request.head.repo.fork + if: (github.event_name == 'push' || github.event.pull_request.head.repo.fork) && (github.event_name != 'push' || github.event.head_commit.message != 'codegen metadata') permissions: contents: read id-token: write steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Set up Node - uses: actions/setup-node@v4 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: - node-version: '20' + node-version: '22' - name: Bootstrap run: ./scripts/bootstrap @@ -55,29 +57,44 @@ jobs: run: ./scripts/build - name: Get GitHub OIDC Token - if: github.repository == 'stainless-sdks/beagle-typescript' + if: |- + github.repository == 'stainless-sdks/beagle-typescript' && + !startsWith(github.ref, 'refs/heads/stl/') id: github-oidc - uses: actions/github-script@v6 + uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 with: script: core.setOutput('github_token', await core.getIDToken()); - name: Upload tarball - if: github.repository == 'stainless-sdks/beagle-typescript' + if: |- + github.repository == 'stainless-sdks/beagle-typescript' && + !startsWith(github.ref, 'refs/heads/stl/') env: URL: https://pkg.stainless.com/s 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/beagle-typescript' && + !startsWith(github.ref, 'refs/heads/stl/') + env: + URL: https://pkg.stainless.com/s?subpackage=mcp-server + AUTH: ${{ steps.github-oidc.outputs.github_token }} + SHA: ${{ github.sha }} + BASE_PATH: packages/mcp-server + run: ./scripts/utils/upload-artifact.sh test: timeout-minutes: 10 name: test runs-on: ${{ github.repository == 'stainless-sdks/beagle-typescript' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} if: github.event_name == 'push' || github.event.pull_request.head.repo.fork steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Set up Node - uses: actions/setup-node@v4 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 with: node-version: '22' diff --git a/.github/workflows/publish-npm.yml b/.github/workflows/publish-npm.yml new file mode 100644 index 00000000..e7340e04 --- /dev/null +++ b/.github/workflows/publish-npm.yml @@ -0,0 +1,51 @@ +# 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/corgi-tech/beagle-sdks/actions/workflows/publish-npm.yml +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] + +jobs: + publish: + name: publish + runs-on: ubuntu-latest + permissions: + contents: write + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + + - name: Set up Node + uses: actions/setup-node@3235b876344d2a9aa001b8d1453c930bba69e610 # v3.9.1 + with: + node-version: '20' + + - name: Install dependencies + run: | + yarn install + + - name: Publish to NPM + run: | + if [ -n "$INPUT_PATH" ]; then + PATHS_RELEASED="[\"$INPUT_PATH\"]" + else + PATHS_RELEASED='[\".\", \"packages/mcp-server\"]' + fi + yarn tsn scripts/publish-packages.ts "{ \"paths_released\": \"$PATHS_RELEASED\" }" + env: + INPUT_PATH: ${{ github.event.inputs.path }} + NPM_TOKEN: ${{ secrets.BEAGLE_NPM_TOKEN || secrets.NPM_TOKEN }} + + - name: Upload MCP Server DXT GitHub release asset + run: | + gh release upload ${{ github.event.release.tag_name }} \ + packages/mcp-server/corgi_tech_beagle_api.mcpb + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/release-doctor.yml b/.github/workflows/release-doctor.yml new file mode 100644 index 00000000..cb7328b1 --- /dev/null +++ b/.github/workflows/release-doctor.yml @@ -0,0 +1,21 @@ +name: Release Doctor +on: + pull_request: + branches: + - main + workflow_dispatch: + +jobs: + release_doctor: + name: release doctor + runs-on: ubuntu-latest + if: github.repository == 'corgi-tech/beagle-sdks' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch' || startsWith(github.head_ref, 'release-please') || github.head_ref == 'next') + + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + + - name: Check release environment + run: | + bash ./bin/check-release-environment + env: + NPM_TOKEN: ${{ secrets.BEAGLE_NPM_TOKEN || secrets.NPM_TOKEN }} diff --git a/.gitignore b/.gitignore index d98d51a8..b7d4f6b9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ .prism.log +.stdy.log node_modules yarn-error.log codegen.log @@ -7,4 +8,6 @@ dist dist-deno /*.tgz .idea/ - +.eslintcache +dist-bundle +*.mcpb diff --git a/.prettierignore b/.prettierignore index 7cc13dd1..36afd3b3 100644 --- a/.prettierignore +++ b/.prettierignore @@ -2,6 +2,7 @@ CHANGELOG.md /ecosystem-tests/*/** /node_modules /deno +/packages/mcp-server/manifest.json # don't format tsc output, will break source maps dist diff --git a/.release-please-manifest.json b/.release-please-manifest.json new file mode 100644 index 00000000..895bf0e3 --- /dev/null +++ b/.release-please-manifest.json @@ -0,0 +1,3 @@ +{ + ".": "2.0.0" +} diff --git a/.stats.yml b/.stats.yml index a7322dc8..c31d9ad5 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ -configured_endpoints: 22 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/corgi%2Fbeagle-908d2651f3ed6cddeba543bca341006e4bd15ff2f1bb1fd4442b896d7c66c547.yml -openapi_spec_hash: 33e9e4dc59e701afb846264d6fa1915e -config_hash: 4309531b38d4521cda66ab537f120fd5 +configured_endpoints: 18 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/corgi/beagle-561a4b9ddd891c8254be3d774ba13871197ce79b11e00ad692e591f991290fc3.yml +openapi_spec_hash: 9a6cedbb9cea871f5d9c5634cf3f5f2a +config_hash: a50e91a2233ab4faad057e676e3cfe49 diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..980351f9 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,192 @@ +# Changelog + +## 2.0.0 (2026-06-17) + +Full Changelog: [v0.0.1-alpha.0...v2.0.0](https://github.com/corgi-tech/beagle-sdks/compare/v0.0.1-alpha.0...v2.0.0) + +### Features + +* **api:** add webhooks & insurance verification ([8149e9c](https://github.com/corgi-tech/beagle-sdks/commit/8149e9c8f5013101ee1b11565d95bc4c6407f846)) +* **api:** api update ([0c269da](https://github.com/corgi-tech/beagle-sdks/commit/0c269da5d141f9bfeb3cf436155a4dcfaa99175c)) +* **api:** api update ([5c36448](https://github.com/corgi-tech/beagle-sdks/commit/5c36448ceff1f3707c24c9ddd48f7abb9dd1f54f)) +* **api:** api update ([42a0b38](https://github.com/corgi-tech/beagle-sdks/commit/42a0b38101cd39e519a17d860f906d2ad12a4a55)) +* **api:** api update ([fec1f3c](https://github.com/corgi-tech/beagle-sdks/commit/fec1f3c507df6780b0e93d6ff07310f383b533e6)) +* **api:** api update ([6f0df5b](https://github.com/corgi-tech/beagle-sdks/commit/6f0df5be92a58371b17915bc82e305e5be5f5cc6)) +* **api:** api update ([69cd92b](https://github.com/corgi-tech/beagle-sdks/commit/69cd92bb960311538f857859a99bfd75191be650)) +* **api:** api update ([3b62b6d](https://github.com/corgi-tech/beagle-sdks/commit/3b62b6d6f4dccf2b11aec39e363fae8ebc9f1e60)) +* **api:** api update ([dd8e619](https://github.com/corgi-tech/beagle-sdks/commit/dd8e619d252ab2568fd779a79449789628f6eb4c)) +* **api:** api update ([d60812e](https://github.com/corgi-tech/beagle-sdks/commit/d60812edd7fba4a49d43cd19f05f5c0a0cdc19eb)) +* **api:** api update ([9a160cf](https://github.com/corgi-tech/beagle-sdks/commit/9a160cf9ab6b99e57419fe01d6ee38a9278ad558)) +* **api:** api update ([ff22357](https://github.com/corgi-tech/beagle-sdks/commit/ff2235783f30d1331d845693dbdd1347bc4b4795)) +* **api:** api update ([23c1441](https://github.com/corgi-tech/beagle-sdks/commit/23c144132a69e9703f64c1700ab693dcee45dac4)) +* **api:** api update ([df35c3f](https://github.com/corgi-tech/beagle-sdks/commit/df35c3f62a43d2cb86a96e00614568e7f1ec2c65)) +* **api:** api update ([dabc9a7](https://github.com/corgi-tech/beagle-sdks/commit/dabc9a7d69d81803d8ace73720b62f6002eac2f3)) +* **api:** api update ([1757c43](https://github.com/corgi-tech/beagle-sdks/commit/1757c430c970516be9002d1f6c341e123193a54a)) +* **api:** api update ([d467235](https://github.com/corgi-tech/beagle-sdks/commit/d4672351a7941a0395c9b23baaff9cacc179b93e)) +* **api:** api update ([7477c2d](https://github.com/corgi-tech/beagle-sdks/commit/7477c2dbdd36f8ab00abb2dc0b34864417a09558)) +* **api:** api update ([6700d42](https://github.com/corgi-tech/beagle-sdks/commit/6700d42958cc9db8ce4e13667d6e960b035a813c)) +* **api:** api update ([e17398f](https://github.com/corgi-tech/beagle-sdks/commit/e17398f8d36c6a5f4d4f1cda0f47957b2f9aa76b)) +* **api:** api update ([2bb87b2](https://github.com/corgi-tech/beagle-sdks/commit/2bb87b26625aac745e42fc2ef606ad6acce5e6a8)) +* **api:** api update ([9e66c0b](https://github.com/corgi-tech/beagle-sdks/commit/9e66c0b05880780f87299cd2cea9ae0e81d6ef25)) +* **api:** api update ([2a8eeca](https://github.com/corgi-tech/beagle-sdks/commit/2a8eecaa6191beac6da67a2be4ad820b2b9b2450)) +* **api:** manual updates ([b34cc40](https://github.com/corgi-tech/beagle-sdks/commit/b34cc40199fbf95a29f862317c8cbd8c17f4be8b)) +* **api:** pagination to readme ([af15627](https://github.com/corgi-tech/beagle-sdks/commit/af156274e9a58cadb3fae6da02c45211218b0d3c)) +* **api:** test cleanup on webhook endpoint shapes ([9c55bea](https://github.com/corgi-tech/beagle-sdks/commit/9c55bea27f36f88963b6f5871fe782edee7f7497)) +* **api:** update via SDK Studio ([8b15707](https://github.com/corgi-tech/beagle-sdks/commit/8b15707e6f80fd03e815e73f8751c9a3d9564148)) +* **api:** update via SDK Studio ([93c377f](https://github.com/corgi-tech/beagle-sdks/commit/93c377f9bcec660e053d242e5985c4145f73cebd)) +* **api:** update via SDK Studio ([e6ebc26](https://github.com/corgi-tech/beagle-sdks/commit/e6ebc2632bec4667cc6b4de5c7cd0c2af54cf3c2)) +* **api:** update via SDK Studio ([3e0ec8d](https://github.com/corgi-tech/beagle-sdks/commit/3e0ec8dd48f106ceca16908d6e7858cb1b7363ac)) +* **api:** update via SDK Studio ([b5a69d1](https://github.com/corgi-tech/beagle-sdks/commit/b5a69d1a994a018668be8254dab658a754616db8)) +* **api:** update via SDK Studio ([9b14796](https://github.com/corgi-tech/beagle-sdks/commit/9b14796531547df45f091696005a78ae34702cc6)) +* **api:** update via SDK Studio ([89182da](https://github.com/corgi-tech/beagle-sdks/commit/89182da970016190ad315ffbadcb34285af09754)) +* **api:** update via SDK Studio ([2b9b95c](https://github.com/corgi-tech/beagle-sdks/commit/2b9b95c2b89b8832be15cdeaa5a34ad3cd7d57c0)) +* **api:** update via SDK Studio ([c4da553](https://github.com/corgi-tech/beagle-sdks/commit/c4da553d9d4ce8295ddf8444db1248889f54cbae)) +* **api:** update via SDK Studio ([5e544fc](https://github.com/corgi-tech/beagle-sdks/commit/5e544fc2d293862013faa86f5c4321eeb65f034c)) +* **api:** update via SDK Studio ([7f7d437](https://github.com/corgi-tech/beagle-sdks/commit/7f7d437702e6dddbc3f71f0b59ae469bcf662028)) +* **client:** add support for endpoint-specific base URLs ([12d7a7a](https://github.com/corgi-tech/beagle-sdks/commit/12d7a7a41360d437dd6c7b76c6d8cfe7e3bb58a4)) +* **mcp:** add code execution tool ([1269066](https://github.com/corgi-tech/beagle-sdks/commit/1269066e553182727ad21f6458022e6d83f35cab)) +* **mcp:** add logging when environment variable is set ([845ad08](https://github.com/corgi-tech/beagle-sdks/commit/845ad086e76de9a3e4e5bd5cdca12771c51c02f6)) +* **mcp:** add option to infer mcp client ([1aa1c09](https://github.com/corgi-tech/beagle-sdks/commit/1aa1c092c2892d5ccf86f67936b847e6b1900ca9)) +* **mcp:** add unix socket option for remote MCP ([9b0fb4c](https://github.com/corgi-tech/beagle-sdks/commit/9b0fb4c376c1d5909bb956dca146532574744d7d)) +* **mcp:** allow setting logging level ([1a551d1](https://github.com/corgi-tech/beagle-sdks/commit/1a551d182e06c6d83d5b5a56abfecbf53728b195)) +* **mcp:** expose client options in `streamableHTTPApp` ([9b6b5ee](https://github.com/corgi-tech/beagle-sdks/commit/9b6b5ee4ca24115f8723fb85733a1137d2e042f4)) +* **mcp:** fallback for void-typed methods ([9df18b9](https://github.com/corgi-tech/beagle-sdks/commit/9df18b9b58478de4dfa6a52f31e504ffab0b8ad2)) +* **mcp:** implement support for binary responses ([457b771](https://github.com/corgi-tech/beagle-sdks/commit/457b771d93b6d61909fc6d18ca299cf6eaad3e7c)) +* **mcp:** parse query string as mcp client options in mcp server ([913561f](https://github.com/corgi-tech/beagle-sdks/commit/913561f27fbaa093f44c8b7a32c2b921d8bb621a)) +* **mcp:** remote server with passthru auth ([08c8116](https://github.com/corgi-tech/beagle-sdks/commit/08c8116423ba4e0fe4f8f73c64de5ac45ea0aea2)) +* **mcp:** set X-Stainless-MCP header ([a9a55d5](https://github.com/corgi-tech/beagle-sdks/commit/a9a55d578a4c341ed0fc81f7a015581509194704)) +* **mcp:** support filtering tool results by a jq expression ([f4996f0](https://github.com/corgi-tech/beagle-sdks/commit/f4996f0ebfe928dbb382e1adfb3de2e56644be80)) + + +### Bug Fixes + +* **client:** explicitly copy fetch in withOptions ([6549425](https://github.com/corgi-tech/beagle-sdks/commit/654942593380202fa00df5be51143eba81da112a)) +* **client:** get fetchOptions type more reliably ([b493b26](https://github.com/corgi-tech/beagle-sdks/commit/b493b26282497995feeaeb771a4574e284a4e567)) +* **client:** send content-type header for requests with an omitted optional body ([2d6cec6](https://github.com/corgi-tech/beagle-sdks/commit/2d6cec653e60c235ce151ed55f179bdc6751a5c3)) +* compat with more runtimes ([d55ea65](https://github.com/corgi-tech/beagle-sdks/commit/d55ea654fe9046bd2d8b9ee862dba00dbacb194c)) +* **mcp:** avoid sending `jq_filter` to base API ([1f865ce](https://github.com/corgi-tech/beagle-sdks/commit/1f865ceabad29ea8ea696c4553ddd096b3a26c19)) +* **mcp:** include required section for top-level properties and support naming transformations ([e9ffc0e](https://github.com/corgi-tech/beagle-sdks/commit/e9ffc0ed916dfe1d31e71e716106c828812e7059)) +* **mcp:** relax input type for asTextContextResult ([0fc1bad](https://github.com/corgi-tech/beagle-sdks/commit/0fc1bad413b3171b03e941df0f7fc0efe9d77f42)) +* **mcp:** reverse validJson capability option and limit scope ([bd146b5](https://github.com/corgi-tech/beagle-sdks/commit/bd146b56ffd0cde779cfc7d8ed67ac730599a916)) +* **mcp:** support jq filtering on cloudflare workers ([180be3d](https://github.com/corgi-tech/beagle-sdks/commit/180be3d22bc81db6ed84550dfa768c6959611d39)) +* publish script — handle NPM errors correctly ([3cf171d](https://github.com/corgi-tech/beagle-sdks/commit/3cf171df9c776f8bb7c6bee4e0f735de5b48062b)) +* treat text/plan with format: binary as raw upload ([8592006](https://github.com/corgi-tech/beagle-sdks/commit/8592006382aaaab8abd85c5a4515ba6ab225da6d)) + + +### Chores + +* add docs to RequestOptions type ([2b4bf74](https://github.com/corgi-tech/beagle-sdks/commit/2b4bf74f010ff4aaf5d938749754bc598f1697e7)) +* add package to package.json ([0f2b02d](https://github.com/corgi-tech/beagle-sdks/commit/0f2b02d59a17e84238fdedffae2e880dfb6984e4)) +* adjust eslint.config.mjs ignore pattern ([268fc7f](https://github.com/corgi-tech/beagle-sdks/commit/268fc7f0a41f18ad0630d0e3b1fb1b5c5a595740)) +* avoid type error in certain environments ([c2488b6](https://github.com/corgi-tech/beagle-sdks/commit/c2488b6e29a721fc22b04498a691da5e4266bc2e)) +* change publish docs url ([5226de4](https://github.com/corgi-tech/beagle-sdks/commit/5226de443388f1a2bc9bb7f636c4fb3ba9c9b505)) +* ci build action ([c24a150](https://github.com/corgi-tech/beagle-sdks/commit/c24a15020445287f2bbbc840d0cd5367079a8587)) +* **ci:** enable for pull requests ([92aaedf](https://github.com/corgi-tech/beagle-sdks/commit/92aaedff0002fb02460065292b973d0f44800f94)) +* **ci:** only run for pushes and fork pull requests ([608e883](https://github.com/corgi-tech/beagle-sdks/commit/608e883362fba20a007ccdbb1d742b3fa76e0b91)) +* **client:** improve path param validation ([334ab9c](https://github.com/corgi-tech/beagle-sdks/commit/334ab9cff9ab1f527ec33fa3b1e5371f30a50f78)) +* **client:** qualify global Blob ([bca52b4](https://github.com/corgi-tech/beagle-sdks/commit/bca52b4ab63b8ad10207c10e3b91bf745e842919)) +* **client:** refactor imports ([bcb6e5e](https://github.com/corgi-tech/beagle-sdks/commit/bcb6e5ee13135bead90e57b00f1a2e98c44f58cf)) +* configure new SDK language ([b9ee214](https://github.com/corgi-tech/beagle-sdks/commit/b9ee2140c2996771561ce50b616249cba930cf0b)) +* configure new SDK language ([f9210d8](https://github.com/corgi-tech/beagle-sdks/commit/f9210d829fd150f0e8d9c4376d3e37996d9a19e8)) +* **deps:** bump eslint-plugin-prettier ([a05d9c3](https://github.com/corgi-tech/beagle-sdks/commit/a05d9c387dd734d32d84e51438d095bb65b0b8fe)) +* **deps:** update dependency @types/node to v20.17.58 ([f1f23d5](https://github.com/corgi-tech/beagle-sdks/commit/f1f23d5d2ef771d8ee07eccef54fce0091923bf3)) +* **docs:** use top-level-await in example snippets ([d28eba3](https://github.com/corgi-tech/beagle-sdks/commit/d28eba32d2514892f49e68647437e2b2a96156ea)) +* **internal:** add pure annotations, make base APIResource abstract ([bafb575](https://github.com/corgi-tech/beagle-sdks/commit/bafb575b158eceedc5e3f9d5b938de69e120b6ed)) +* **internal:** codegen related update ([5c4f119](https://github.com/corgi-tech/beagle-sdks/commit/5c4f119f0667c84a2568b389f96b0c5c967fa3d9)) +* **internal:** codegen related update ([005dc9e](https://github.com/corgi-tech/beagle-sdks/commit/005dc9ef1631dc82e17411f8428d80d4457f80cc)) +* **internal:** codegen related update ([d49d7e5](https://github.com/corgi-tech/beagle-sdks/commit/d49d7e5e4a552e90b6b3c14788a8ca6dea09c004)) +* **internal:** codegen related update ([d48674e](https://github.com/corgi-tech/beagle-sdks/commit/d48674e4ff226a997fe0e791e908369cea5b149b)) +* **internal:** codegen related update ([516b897](https://github.com/corgi-tech/beagle-sdks/commit/516b897c6fd16266a8ad5b3f0d1850053a08d454)) +* **internal:** codegen related update ([f7d0710](https://github.com/corgi-tech/beagle-sdks/commit/f7d0710eaf076b3cdd60715492cdca08da33ed00)) +* **internal:** codegen related update ([52de4bb](https://github.com/corgi-tech/beagle-sdks/commit/52de4bb952e65b0cbc6ef5831cace103b6ce4f33)) +* **internal:** codegen related update ([77ae117](https://github.com/corgi-tech/beagle-sdks/commit/77ae117e0b84e00817bb1aa7f84cdb39cd95796c)) +* **internal:** codegen related update ([14bac3e](https://github.com/corgi-tech/beagle-sdks/commit/14bac3e858c0e5f2a22d2b6d46fdfd1f54ea68c0)) +* **internal:** codegen related update ([a435a45](https://github.com/corgi-tech/beagle-sdks/commit/a435a4578c8992d07627a8d746317b4737401d42)) +* **internal:** codegen related update ([ac5e463](https://github.com/corgi-tech/beagle-sdks/commit/ac5e4635baa292446c0ac188467401aac01fd2a7)) +* **internal:** codegen related update ([46f241e](https://github.com/corgi-tech/beagle-sdks/commit/46f241ecc68ec680b7ce8b1f4e6971328a95b625)) +* **internal:** codegen related update ([e9f78b1](https://github.com/corgi-tech/beagle-sdks/commit/e9f78b10d52231401dab603ec28a5c934063dc9a)) +* **internal:** codegen related update ([3731058](https://github.com/corgi-tech/beagle-sdks/commit/37310585b45733f820ba36bf7accd30b5abe2c30)) +* **internal:** codegen related update ([f8e55dc](https://github.com/corgi-tech/beagle-sdks/commit/f8e55dc9a6aca74d52d2137f9c4ef711801a818d)) +* **internal:** codegen related update ([a964764](https://github.com/corgi-tech/beagle-sdks/commit/a964764acd8d0ff492707aee8b4aaeb0d25f261c)) +* **internal:** codegen related update ([0811822](https://github.com/corgi-tech/beagle-sdks/commit/08118229a18bc20e69ff03e53fb69b2f5dd6cbd5)) +* **internal:** codegen related update ([e76d478](https://github.com/corgi-tech/beagle-sdks/commit/e76d478464cad7d133de1759662af827074ccb5a)) +* **internal:** codegen related update ([5062a2c](https://github.com/corgi-tech/beagle-sdks/commit/5062a2c25ad7601b8d0da820cd2f500757828885)) +* **internal:** codegen related update ([b749c77](https://github.com/corgi-tech/beagle-sdks/commit/b749c77c8a7bcec61090e4ffed69a9af715ec390)) +* **internal:** codegen related update ([1456ba6](https://github.com/corgi-tech/beagle-sdks/commit/1456ba62ee4641021cb2aef893588bffc71d791e)) +* **internal:** codegen related update ([4b5a662](https://github.com/corgi-tech/beagle-sdks/commit/4b5a6626ff1f3ce289c7a2bc25b3fb200f6beeaf)) +* **internal:** codegen related update ([5b04161](https://github.com/corgi-tech/beagle-sdks/commit/5b0416129e941ab2cf00b73a3748d9edc491fb94)) +* **internal:** codegen related update ([d1bdeb7](https://github.com/corgi-tech/beagle-sdks/commit/d1bdeb77d1a6d0e46e67e6d4865f7d0da0d689a7)) +* **internal:** codegen related update ([94258ad](https://github.com/corgi-tech/beagle-sdks/commit/94258adedfbaf1272f7d137b5e10b5b9270c3b5a)) +* **internal:** codegen related update ([440ae15](https://github.com/corgi-tech/beagle-sdks/commit/440ae1570850aa44c6e74c1b0ef5266589e7c883)) +* **internal:** codegen related update ([7e137eb](https://github.com/corgi-tech/beagle-sdks/commit/7e137eba30e258562dcafff4078da074e20ff482)) +* **internal:** codegen related update ([b0f7b26](https://github.com/corgi-tech/beagle-sdks/commit/b0f7b26a49fbfbf9bf5223f29419417be2db7214)) +* **internal:** codegen related update ([64360c0](https://github.com/corgi-tech/beagle-sdks/commit/64360c0082d42f064984c9f4deb37e0004c1c9fa)) +* **internal:** codegen related update ([be604b5](https://github.com/corgi-tech/beagle-sdks/commit/be604b5893ff914f86c895ea90d22baaddc8535d)) +* **internal:** codegen related update ([37d999e](https://github.com/corgi-tech/beagle-sdks/commit/37d999e60811093717bbe1d5ff8def0042c9b359)) +* **internal:** codegen related update ([522fc90](https://github.com/corgi-tech/beagle-sdks/commit/522fc908bf543d920f7d6e1dd17b16a233532064)) +* **internal:** codegen related update ([ba5a41e](https://github.com/corgi-tech/beagle-sdks/commit/ba5a41e81c157bc49fda7d9bff1ab01e960d4bfc)) +* **internal:** codegen related update ([40f63e2](https://github.com/corgi-tech/beagle-sdks/commit/40f63e208dd454a7f2d68ebe64e419b7f1becb3a)) +* **internal:** codegen related update ([9bb2822](https://github.com/corgi-tech/beagle-sdks/commit/9bb2822d8a46d582cd0042ee5b22dc837cd8babc)) +* **internal:** codegen related update ([f51ff81](https://github.com/corgi-tech/beagle-sdks/commit/f51ff818983d9d6474a8b367e8d3d9c8ddec1429)) +* **internal:** codegen related update ([7247d7b](https://github.com/corgi-tech/beagle-sdks/commit/7247d7ba2bf1e0a328d1a04a8d6754b70798a2ad)) +* **internal:** codegen related update ([e3d038e](https://github.com/corgi-tech/beagle-sdks/commit/e3d038e4263c54d5f76209f881b25292b5451dfe)) +* **internal:** codegen related update ([d01b7ab](https://github.com/corgi-tech/beagle-sdks/commit/d01b7ab283ec4fa0e8bb75b394ec699e8faa074d)) +* **internal:** codegen related update ([e0d836a](https://github.com/corgi-tech/beagle-sdks/commit/e0d836ab92ff11783082dc87b1c82e8f290cba7c)) +* **internal:** codegen related update ([82117a6](https://github.com/corgi-tech/beagle-sdks/commit/82117a62e14c3a1ac72fc3c632c7fb21b7934d94)) +* **internal:** codegen related update ([94390bc](https://github.com/corgi-tech/beagle-sdks/commit/94390bc6b29e976c0a83036f1bb11a111cad63ba)) +* **internal:** codegen related update ([8bd9741](https://github.com/corgi-tech/beagle-sdks/commit/8bd9741143afb8665684c198b15d08ae54c5d6a1)) +* **internal:** codegen related update ([0051b46](https://github.com/corgi-tech/beagle-sdks/commit/0051b46e8c6000d1938afea968f748d4941b08f7)) +* **internal:** codegen related update ([6cfc7a2](https://github.com/corgi-tech/beagle-sdks/commit/6cfc7a2759e7509d7b58253a835629598da380a2)) +* **internal:** codegen related update ([3c63419](https://github.com/corgi-tech/beagle-sdks/commit/3c63419f86cd723812abc2984d6ca518f32d8ad4)) +* **internal:** codegen related update ([e54e04f](https://github.com/corgi-tech/beagle-sdks/commit/e54e04f77fc224bd3488ac7ef09738788af68071)) +* **internal:** codegen related update ([f141204](https://github.com/corgi-tech/beagle-sdks/commit/f141204909ece06b927458df3dc99c23d3f0a3ee)) +* **internal:** codegen related update ([b346b4a](https://github.com/corgi-tech/beagle-sdks/commit/b346b4a57a5aaf2b7531daf166e5ba375c98e2f9)) +* **internal:** codegen related update ([198914f](https://github.com/corgi-tech/beagle-sdks/commit/198914f82467d8c6500b9f93f899d873c07550ff)) +* **internal:** codegen related update ([4737470](https://github.com/corgi-tech/beagle-sdks/commit/473747085794925217e3c7e9e78acb21319cd87e)) +* **internal:** codegen related update ([cb1b2de](https://github.com/corgi-tech/beagle-sdks/commit/cb1b2de75afc69765dc42d832b5a6cac991061b0)) +* **internal:** codegen related update ([c51b535](https://github.com/corgi-tech/beagle-sdks/commit/c51b5357383a5a86f6592d8af2b9ccd3e357c29e)) +* **internal:** codegen related update ([a880b1a](https://github.com/corgi-tech/beagle-sdks/commit/a880b1a570f52404fab4d0fcc47f4dc4867e89eb)) +* **internal:** codegen related update ([4077f6d](https://github.com/corgi-tech/beagle-sdks/commit/4077f6d678b4bfdf8744a00eece23c95ac55dc16)) +* **internal:** codegen related update ([16d3d7b](https://github.com/corgi-tech/beagle-sdks/commit/16d3d7bcc7a5220540f4aa8e83212e84da468713)) +* **internal:** codegen related update ([98aac60](https://github.com/corgi-tech/beagle-sdks/commit/98aac60cf6ad782f8fd720d59e4edf8938409eb5)) +* **internal:** codegen related update ([ef25521](https://github.com/corgi-tech/beagle-sdks/commit/ef25521707cb8fa31d9df40ce441eef11ccd105e)) +* **internal:** codegen related update ([a10002e](https://github.com/corgi-tech/beagle-sdks/commit/a10002e54a632b7f5d0cd01d5c53314f7883f3c2)) +* **internal:** codegen related update ([c9154b5](https://github.com/corgi-tech/beagle-sdks/commit/c9154b5f6fba930499648e4b8669e2d13916c6b8)) +* **internal:** codegen related update ([4eb7b49](https://github.com/corgi-tech/beagle-sdks/commit/4eb7b49c60ac79cd3e0270ca2c43eac0444bda94)) +* **internal:** codegen related update ([26017f0](https://github.com/corgi-tech/beagle-sdks/commit/26017f0bd142599771f2e63665bf317131db31bb)) +* **internal:** codegen related update ([394b044](https://github.com/corgi-tech/beagle-sdks/commit/394b04426e6469324b8bc42a1ad94b70b64666a1)) +* **internal:** codegen related update ([f28b947](https://github.com/corgi-tech/beagle-sdks/commit/f28b947295c7808fe071081c6f2a856cfc124661)) +* **internal:** fix MCP Dockerfiles so they can be built without buildkit ([f15f82d](https://github.com/corgi-tech/beagle-sdks/commit/f15f82d8febe62f4c13529feea47c012e8d397f9)) +* **internal:** fix MCP Dockerfiles so they can be built without buildkit ([29a6f08](https://github.com/corgi-tech/beagle-sdks/commit/29a6f084bf441b4c61979f944fdab9c65bf0c8a3)) +* **internal:** fix readablestream types in node 20 ([153e54c](https://github.com/corgi-tech/beagle-sdks/commit/153e54cfa4b3bf0a1e39f4e925119b54a5e92d0e)) +* **internal:** formatting change ([15c4306](https://github.com/corgi-tech/beagle-sdks/commit/15c4306447ee4b4c5ca0e56d6ca29c21f5b6b81c)) +* **internal:** make MCP code execution location configurable via a flag ([de56d4a](https://github.com/corgi-tech/beagle-sdks/commit/de56d4a0f82afcc062322e36e8fab75d2e53bde1)) +* **internal:** make mcp-server publishing public by defaut ([4ea87da](https://github.com/corgi-tech/beagle-sdks/commit/4ea87dae173727b8986c870617f082cb9f05d239)) +* **internal:** move publish config ([b5d9c06](https://github.com/corgi-tech/beagle-sdks/commit/b5d9c06694a66d1c3785238ee392a9576b7dbcf8)) +* **internal:** refactor array check ([e721304](https://github.com/corgi-tech/beagle-sdks/commit/e7213041b460d7fd3cafb0c30aa32a9cf5222d67)) +* **internal:** remove redundant imports config ([00033c0](https://github.com/corgi-tech/beagle-sdks/commit/00033c0b2ea16c042bdc0d2ce1405875f833b10a)) +* **internal:** update comment in script ([23b9927](https://github.com/corgi-tech/beagle-sdks/commit/23b9927106007dbe0f20607802049ba138b87df0)) +* **internal:** update global Error reference ([f2029a0](https://github.com/corgi-tech/beagle-sdks/commit/f2029a0d8e693520ead61b89b9e8516f5956f93f)) +* **internal:** update jest config ([968f16f](https://github.com/corgi-tech/beagle-sdks/commit/968f16f1be5f373bdb651f9ffd8ebad80915d983)) +* **internal:** upgrade @modelcontextprotocol/sdk and hono ([b7ed22d](https://github.com/corgi-tech/beagle-sdks/commit/b7ed22d46820f5f6e4c0a94fde9abe8e0d0d3dfb)) +* make some internal functions async ([03dca37](https://github.com/corgi-tech/beagle-sdks/commit/03dca37a869de6f32a9ea7db5a3478fd2fbcc2e4)) +* **mcp-server:** increase local docs search result count from 5 to 10 ([ac3f8d4](https://github.com/corgi-tech/beagle-sdks/commit/ac3f8d44484c8467f83f3cd1bc59c68b0221406d)) +* **mcp:** add cors to oauth metadata route ([2810aab](https://github.com/corgi-tech/beagle-sdks/commit/2810aabc88f2ea8693242e1a64448eb776b7c549)) +* **mcp:** correctly update version in sync with sdk ([3631698](https://github.com/corgi-tech/beagle-sdks/commit/363169875585a0166881b7b11a12a096a11a388c)) +* **mcp:** document remote server in README.md ([03fd93c](https://github.com/corgi-tech/beagle-sdks/commit/03fd93c9d0ca98f782ebc099daed25817249b434)) +* **mcp:** formatting ([96e93b3](https://github.com/corgi-tech/beagle-sdks/commit/96e93b33f65a890973af7ef80ee18052d60163a4)) +* **mcp:** minor cleanup of types and package.json ([e8a0802](https://github.com/corgi-tech/beagle-sdks/commit/e8a08021d50b3988cd70f0580d4d42422f5b47ea)) +* **mcp:** provides high-level initMcpServer function and exports known clients ([7f2e621](https://github.com/corgi-tech/beagle-sdks/commit/7f2e6216ed98f9f684b7354a228744bdf14b7cf1)) +* **mcp:** refactor streamable http transport ([5667ecd](https://github.com/corgi-tech/beagle-sdks/commit/5667ecd222a0c35e996521a08e995d18ce0d5be3)) +* **mcp:** rework imports in tools ([9d6e556](https://github.com/corgi-tech/beagle-sdks/commit/9d6e556504b526cb6b76cb190f0ee7fe01f68711)) +* **mcp:** up tsconfig lib version to es2022 ([7677185](https://github.com/corgi-tech/beagle-sdks/commit/767718501422e254729875742c8270dd7d91181d)) +* **mcp:** update package.json ([e99397d](https://github.com/corgi-tech/beagle-sdks/commit/e99397d9130edff0386eb934326798ba27d328a9)) +* **mcp:** update README ([5c2b02c](https://github.com/corgi-tech/beagle-sdks/commit/5c2b02cc28ea854c4203099f5e1e0cdeb89c29fd)) +* **mcp:** update types ([5be8de2](https://github.com/corgi-tech/beagle-sdks/commit/5be8de2a75dde75febba09c8e1465e820863dc8a)) +* **readme:** update badges ([501f0ba](https://github.com/corgi-tech/beagle-sdks/commit/501f0ba759def316457bcfedb99cc06bd4ddb602)) +* **readme:** use better example snippet for undocumented params ([84490d0](https://github.com/corgi-tech/beagle-sdks/commit/84490d07e47c61b75314b2f25bd3a5b2fd51f3d4)) +* **ts:** reorder package.json imports ([cae3b82](https://github.com/corgi-tech/beagle-sdks/commit/cae3b820bd235b08a073ea4a5f19e84e8dfda76f)) +* update @stainless-api/prism-cli to v5.15.0 ([8010fd8](https://github.com/corgi-tech/beagle-sdks/commit/8010fd881bd4714255779795cf55a4f04fb6f71d)) +* update CI script ([c045122](https://github.com/corgi-tech/beagle-sdks/commit/c045122557e3da1c7a19264db20607e8e3d5d5f8)) +* update SDK settings ([296405d](https://github.com/corgi-tech/beagle-sdks/commit/296405deb7599b4067ce68a0d3e59952d5e3a606)) +* update SDK settings ([7944dbc](https://github.com/corgi-tech/beagle-sdks/commit/7944dbcad7e324e6c3e368f59f5099efdf5f8b9e)) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1eabc7ff..cad8d890 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -42,35 +42,29 @@ 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/beagle-typescript.git +$ npm install git+ssh://git@github.com:corgi-tech/beagle-sdks.git ``` Alternatively, to link a local copy of the repo: ```sh # Clone -$ git clone https://www.github.com/stainless-sdks/beagle-typescript -$ cd beagle-typescript +$ git clone https://www.github.com/corgi-tech/beagle-sdks +$ cd beagle-sdks # With yarn $ yarn link $ cd ../my-package -$ yarn link beagle +$ yarn link @corgi-tech/beagle # With pnpm $ pnpm link --global $ cd ../my-package -$ pnpm link -—global beagle +$ pnpm link --global @corgi-tech/beagle ``` ## 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 ``` @@ -91,3 +85,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/corgi-tech/beagle-sdks/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/LICENSE b/LICENSE index 70f57606..ffaf6d8c 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2025 Beagle + Copyright 2026 Beagle Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/README.md b/README.md index cc92e62e..6e97fdcc 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Beagle TypeScript API Library -[![NPM version]()](https://npmjs.org/package/beagle) ![npm bundle size](https://img.shields.io/bundlephobia/minzip/beagle) +[![NPM version]()](https://npmjs.org/package/@corgi-tech/beagle) ![npm bundle size](https://img.shields.io/bundlephobia/minzip/@corgi-tech/beagle) This library provides convenient access to the Beagle REST API from server-side TypeScript or JavaScript. @@ -8,22 +8,28 @@ The full API of this library can be found in [api.md](api.md). It is generated with [Stainless](https://www.stainless.com/). +## MCP Server + +Use the Beagle MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application. + +[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=%40corgi-tech%2Fbeagle-mcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkBjb3JnaS10ZWNoL2JlYWdsZS1tY3AiXSwiZW52Ijp7IkJFQUdMRV9BUElfS0VZIjoiTXkgQVBJIEtleSJ9fQ) +[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22%40corgi-tech%2Fbeagle-mcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40corgi-tech%2Fbeagle-mcp%22%5D%2C%22env%22%3A%7B%22BEAGLE_API_KEY%22%3A%22My%20API%20Key%22%7D%7D) + +> Note: You may need to set environment variables in your MCP client. + ## Installation ```sh -npm install git+ssh://git@github.com:stainless-sdks/beagle-typescript.git +npm install @corgi-tech/beagle ``` -> [!NOTE] -> Once this package is [published to npm](https://www.stainless.com/docs/guides/publish), this will become: `npm install beagle` - ## Usage The full API of this library can be found in [api.md](api.md). ```js -import Beagle from 'beagle'; +import Beagle from '@corgi-tech/beagle'; const client = new Beagle({ apiKey: process.env['BEAGLE_API_KEY'], // This is the default and can be omitted @@ -31,6 +37,8 @@ const client = new Beagle({ }); const plans = await client.plans.list(); + +console.log(plans.data); ``` ### Request & Response types @@ -39,7 +47,7 @@ This library includes TypeScript definitions for all request params and response ```ts -import Beagle from 'beagle'; +import Beagle from '@corgi-tech/beagle'; const client = new Beagle({ apiKey: process.env['BEAGLE_API_KEY'], // This is the default and can be omitted @@ -125,37 +133,6 @@ On timeout, an `APIConnectionTimeoutError` is thrown. Note that requests which time out will be [retried twice by default](#retries). -## Auto-pagination - -List methods in the Beagle API are paginated. -You can use the `for await … of` syntax to iterate through items across all pages: - -```ts -async function fetchAllTenants(params) { - const allTenants = []; - // Automatically fetches more pages as needed. - for await (const tenant of client.tenants.list()) { - allTenants.push(tenant); - } - return allTenants; -} -``` - -Alternatively, you can request a single page at a time: - -```ts -let page = await client.tenants.list(); -for (const tenant of page.tenants) { - console.log(tenant); -} - -// Convenience methods are provided for manually paginating: -while (page.hasNextPage()) { - page = await page.getNextPage(); - // ... -} -``` - ## Advanced Usage ### Accessing raw Response data (e.g., headers) @@ -176,7 +153,7 @@ console.log(response.statusText); // access the underlying Response object const { data: plans, response: raw } = await client.plans.list().withResponse(); console.log(raw.headers.get('X-My-Header')); -console.log(plans); +console.log(plans.data); ``` ### Logging @@ -193,7 +170,7 @@ The log level can be configured in two ways: 2. Using the `logLevel` client option (overrides the environment variable if set) ```ts -import Beagle from 'beagle'; +import Beagle from '@corgi-tech/beagle'; const client = new Beagle({ logLevel: 'debug', // Show all log messages @@ -221,7 +198,7 @@ When providing a custom logger, the `logLevel` option still controls which messa below the configured level will not be sent to your logger. ```ts -import Beagle from 'beagle'; +import Beagle from '@corgi-tech/beagle'; import pino from 'pino'; const logger = pino(); @@ -290,7 +267,7 @@ globalThis.fetch = fetch; Or pass it to the client: ```ts -import Beagle from 'beagle'; +import Beagle from '@corgi-tech/beagle'; import fetch from 'my-fetch'; const client = new Beagle({ fetch }); @@ -301,7 +278,7 @@ const client = new Beagle({ fetch }); 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 Beagle from 'beagle'; +import Beagle from '@corgi-tech/beagle'; const client = new Beagle({ fetchOptions: { @@ -318,7 +295,7 @@ options to requests: **Node** [[docs](https://github.com/nodejs/undici/blob/main/docs/docs/api/ProxyAgent.md#example---proxyagent-with-fetch)] ```ts -import Beagle from 'beagle'; +import Beagle from '@corgi-tech/beagle'; import * as undici from 'undici'; const proxyAgent = new undici.ProxyAgent('http://localhost:8888'); @@ -332,7 +309,7 @@ const client = new Beagle({ **Bun** [[docs](https://bun.sh/guides/http/proxy)] ```ts -import Beagle from 'beagle'; +import Beagle from '@corgi-tech/beagle'; const client = new Beagle({ fetchOptions: { @@ -344,7 +321,7 @@ const client = new Beagle({ **Deno** [[docs](https://docs.deno.com/api/deno/~/Deno.createHttpClient)] ```ts -import Beagle from 'npm:beagle'; +import Beagle from 'npm:@corgi-tech/beagle'; const httpClient = Deno.createHttpClient({ proxy: { url: 'http://localhost:8888' } }); const client = new Beagle({ @@ -366,7 +343,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/beagle-typescript/issues) with questions, bugs, or suggestions. +We are keen for your feedback; please open an [issue](https://www.github.com/corgi-tech/beagle-sdks/issues) with questions, bugs, or suggestions. ## Requirements diff --git a/api.md b/api.md index 23ce7325..d8cfb5fe 100644 --- a/api.md +++ b/api.md @@ -3,11 +3,12 @@ Types: - Plan +- PlanRetrieveResponse - PlanListResponse Methods: -- client.plans.retrieve(code) -> Plan +- client.plans.retrieve(code) -> PlanRetrieveResponse - client.plans.list() -> PlanListResponse # PropertyManagers @@ -16,13 +17,17 @@ Types: - Pagination - PropertyManager +- PropertyManagerCreateResponse +- PropertyManagerRetrieveResponse +- PropertyManagerUpdateResponse +- PropertyManagerListResponse Methods: -- client.propertyManagers.create({ ...params }) -> PropertyManager -- client.propertyManagers.retrieve(id) -> PropertyManager -- client.propertyManagers.update(id, { ...params }) -> PropertyManager -- client.propertyManagers.list({ ...params }) -> PropertyManagersPropertyManagersPagination +- client.propertyManagers.create({ ...params }) -> PropertyManagerCreateResponse +- client.propertyManagers.retrieve(id) -> PropertyManagerRetrieveResponse +- client.propertyManagers.update(id, { ...params }) -> PropertyManagerUpdateResponse +- client.propertyManagers.list({ ...params }) -> PropertyManagerListResponse - client.propertyManagers.delete(id) -> void # Tenants @@ -32,13 +37,17 @@ Types: - Address - Contact - Tenant +- TenantCreateResponse +- TenantRetrieveResponse +- TenantUpdateResponse +- TenantListResponse Methods: -- client.tenants.create({ ...params }) -> Tenant -- client.tenants.retrieve(id) -> Tenant -- client.tenants.update(id, { ...params }) -> Tenant -- client.tenants.list({ ...params }) -> TenantsTenantsPagination +- client.tenants.create({ ...params }) -> TenantCreateResponse +- client.tenants.retrieve(id) -> TenantRetrieveResponse +- client.tenants.update(id, { ...params }) -> TenantUpdateResponse +- client.tenants.list({ ...params }) -> TenantListResponse - client.tenants.delete(id) -> void # Enrollments @@ -46,13 +55,17 @@ Methods: Types: - Enrollment +- EnrollmentCreateResponse +- EnrollmentRetrieveResponse +- EnrollmentListResponse Methods: -- client.enrollments.create({ ...params }) -> Enrollment -- client.enrollments.retrieve(id) -> Enrollment -- client.enrollments.list({ ...params }) -> EnrollmentsEnrollmentsPagination +- client.enrollments.create({ ...params }) -> EnrollmentCreateResponse +- client.enrollments.retrieve(id) -> EnrollmentRetrieveResponse +- client.enrollments.list({ ...params }) -> EnrollmentListResponse - client.enrollments.lapse(id) -> void +- client.enrollments.retrieveCertificate(id) -> Response # InsuranceVerification @@ -67,18 +80,3 @@ Methods: # Webhook ## Endpoints - -Types: - -- EndpointCreateResponse -- EndpointRetrieveResponse -- EndpointUpdateResponse -- EndpointListResponse - -Methods: - -- client.webhook.endpoints.create({ ...params }) -> EndpointCreateResponse -- client.webhook.endpoints.retrieve(id) -> EndpointRetrieveResponse -- client.webhook.endpoints.update(id, { ...params }) -> EndpointUpdateResponse -- client.webhook.endpoints.list({ ...params }) -> EndpointListResponsesWebhookEndpointsPagination -- client.webhook.endpoints.delete(id) -> void diff --git a/bin/check-release-environment b/bin/check-release-environment new file mode 100644 index 00000000..e4b6d58e --- /dev/null +++ b/bin/check-release-environment @@ -0,0 +1,22 @@ +#!/usr/bin/env bash + +errors=() + +if [ -z "${NPM_TOKEN}" ]; then + 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[@]} + +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/bin/publish-npm b/bin/publish-npm index fa2243d2..45e8aa80 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/eslint.config.mjs b/eslint.config.mjs index e9f86434..9136cc9e 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1,7 +1,6 @@ // @ts-check import tseslint from 'typescript-eslint'; import unusedImports from 'eslint-plugin-unused-imports'; -import prettier from 'eslint-plugin-prettier'; export default tseslint.config( { @@ -14,18 +13,16 @@ export default tseslint.config( 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: '^beagle(/.*)?', + regex: '^@corgi-tech/beagle(/.*)?', message: 'Use a relative import, not a package import.', }, ], diff --git a/jest.config.ts b/jest.config.ts index d5629a6d..af2930e4 100644 --- a/jest.config.ts +++ b/jest.config.ts @@ -7,8 +7,8 @@ const config: JestConfigWithTsJest = { '^.+\\.(t|j)sx?$': ['@swc/jest', { sourceMaps: 'inline' }], }, moduleNameMapper: { - '^beagle$': '/src/index.ts', - '^beagle/(.*)$': '/src/$1', + '^@corgi-tech/beagle$': '/src/index.ts', + '^@corgi-tech/beagle/(.*)$': '/src/$1', }, modulePathIgnorePatterns: [ '/ecosystem-tests/', diff --git a/package.json b/package.json index b71aebcc..835cfbae 100644 --- a/package.json +++ b/package.json @@ -1,18 +1,21 @@ { - "name": "beagle", - "version": "0.0.1-alpha.0", + "name": "@corgi-tech/beagle", + "version": "2.0.0", "description": "The official TypeScript library for the Beagle API", "author": "Beagle <>", "types": "dist/index.d.ts", "main": "dist/index.js", "type": "commonjs", - "repository": "github:stainless-sdks/beagle-typescript", + "repository": "github:corgi-tech/beagle-sdks", "license": "Apache-2.0", "packageManager": "yarn@1.22.22", "files": [ "**/*" ], "private": false, + "publishConfig": { + "access": "public" + }, "scripts": { "test": "./scripts/test", "build": "./scripts/build", @@ -30,11 +33,9 @@ "@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.4.1", + "eslint": "^9.39.1", "eslint-plugin-unused-imports": "^4.1.4", "iconv-lite": "^0.6.3", "jest": "^29.4.0", @@ -42,13 +43,22 @@ "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.11/tsc-multi.tgz", "tsconfig-paths": "^4.0.0", - "typescript": "5.8.3" + "tslib": "^2.8.1", + "typescript": "5.8.3", + "typescript-eslint": "8.31.1" + }, + "overrides": { + "minimatch": "^9.0.5" + }, + "pnpm": { + "overrides": { + "minimatch": "^9.0.5" + } }, - "imports": { - "beagle": ".", - "beagle/*": "./src/*" + "resolutions": { + "minimatch": "^9.0.5" }, "exports": { ".": { diff --git a/packages/mcp-server/Dockerfile b/packages/mcp-server/Dockerfile new file mode 100644 index 00000000..8f2567be --- /dev/null +++ b/packages/mcp-server/Dockerfile @@ -0,0 +1,78 @@ +# Dockerfile for Beagle MCP Server +# +# This Dockerfile builds a Docker image for the MCP Server. +# +# To build the image locally: +# docker build -f packages/mcp-server/Dockerfile -t @corgi-tech/beagle-mcp:local . +# +# To run the image: +# docker run -i @corgi-tech/beagle-mcp:local [OPTIONS] +# +# Common options: +# --tool= Include specific tools +# --resource= Include tools for specific resources +# --operation=read|write Filter by operation type +# --client= Set client compatibility (e.g., claude, cursor) +# --transport= Set transport type (stdio or http) +# +# For a full list of options: +# docker run -i @corgi-tech/beagle-mcp:local --help +# +# Note: The MCP server uses stdio transport by default. Docker's -i flag +# enables interactive mode, allowing the container to communicate over stdin/stdout. + +# Build stage +FROM node:24-alpine AS builder + +# Install bash for build script +RUN apk add --no-cache bash openssl + +# Set working directory +WORKDIR /build + +# Copy entire repository +COPY . . + +# Install all dependencies and build everything +RUN yarn install --frozen-lockfile && \ + yarn build && \ + # Remove the symlink to the SDK so it doesn't interfere with the explicit COPY below + rm -Rf packages/mcp-server/node_modules/@corgi-tech/beagle + +FROM denoland/deno:alpine-2.7.1 + +# Install node and npm +RUN apk add --no-cache nodejs npm + +ENV LD_LIBRARY_PATH=/usr/lib:/usr/local/lib + +# Add non-root user +RUN addgroup -g 1001 -S nodejs && adduser -S nodejs -u 1001 + +# Set working directory +WORKDIR /app + +# Copy the built mcp-server dist directory +COPY --from=builder /build/packages/mcp-server/dist ./ + +# Copy node_modules from mcp-server (includes all production deps) +COPY --from=builder /build/packages/mcp-server/node_modules ./node_modules + +# Copy the built @corgi-tech/beagle into node_modules +COPY --from=builder /build/dist ./node_modules/@corgi-tech/beagle + +# Change ownership to nodejs user +RUN chown -R nodejs:nodejs /app +RUN chown -R nodejs:nodejs /deno-dir + +# Switch to non-root user +USER nodejs + +# The MCP server uses stdio transport by default +# No exposed ports needed for stdio communication + +# Set the entrypoint to the MCP server +ENTRYPOINT ["node", "index.js"] + +# Allow passing arguments to the MCP server +CMD [] diff --git a/packages/mcp-server/README.md b/packages/mcp-server/README.md index e5f69c74..61fe2703 100644 --- a/packages/mcp-server/README.md +++ b/packages/mcp-server/README.md @@ -4,33 +4,18 @@ It is generated with [Stainless](https://www.stainless.com/). ## Installation -### Building +### Direct invocation -Because it's not published yet, clone the repo and build it: +You can run the MCP Server directly via `npx`: ```sh -git clone git@github.com:stainless-sdks/beagle-typescript.git -cd beagle-typescript -./scripts/bootstrap -./scripts/build -``` - -### Running - -```sh -# set env vars as needed export BEAGLE_API_KEY="My API Key" export BEAGLE_ENVIRONMENT="production" -node ./packages/mcp-server/dist/index.js +npx -y @corgi-tech/beagle-mcp@latest ``` -> [!NOTE] -> Once this package is [published to npm](https://www.stainless.com/docs/guides/publish), this will become: `npx -y beagle-mcp` - ### Via MCP Client -[Build the project](#building) as mentioned above. - 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. @@ -39,9 +24,9 @@ For clients with a configuration JSON, it might look something like this: ```json { "mcpServers": { - "beagle_api": { - "command": "node", - "args": ["/path/to/local/beagle-typescript/packages/mcp-server", "--client=claude", "--tools=dynamic"], + "corgi_tech_beagle_api": { + "command": "npx", + "args": ["-y", "@corgi-tech/beagle-mcp"], "env": { "BEAGLE_API_KEY": "My API Key", "BEAGLE_ENVIRONMENT": "production" @@ -51,173 +36,66 @@ For clients with a configuration JSON, it might look something like this: } ``` -## 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 +### Cursor -### Dynamic tools +If you use Cursor, you can install the MCP server by using the button below. You will need to set your environment variables +in Cursor's `mcp.json`, which can be found in Cursor Settings > Tools & MCP > New MCP Server. -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: +[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=%40corgi-tech%2Fbeagle-mcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkBjb3JnaS10ZWNoL2JlYWdsZS1tY3AiXSwiZW52Ijp7IkJFQUdMRV9BUElfS0VZIjoiTXkgQVBJIEtleSJ9fQ) -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 +### VS Code -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. +If you use MCP, you can install the MCP server by clicking the link below. You will need to set your environment variables +in VS Code's `mcp.json`, which can be found via Command Palette > MCP: Open User Configuration. -See more information with `--help`. +[Open VS Code](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22%40corgi-tech%2Fbeagle-mcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40corgi-tech%2Fbeagle-mcp%22%5D%2C%22env%22%3A%7B%22BEAGLE_API_KEY%22%3A%22My%20API%20Key%22%7D%7D) -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 -``` +### Claude Code -2. Exclude specific tools while including others: +If you use Claude Code, you can install the MCP server by running the command below in your terminal. You will need to set your +environment variables in Claude Code's `.claude.json`, which can be found in your home directory. -```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 +claude mcp add corgi_tech_beagle_mcp_api --env BEAGLE_API_KEY="My API Key" -- npx -y @corgi-tech/beagle-mcp ``` -4. Complex filtering with multiple criteria: +## Code Mode -```bash ---resource=cards,accounts --operation=read --tag=kyc --no-tool=create_cards -``` +This MCP server is built on the "Code Mode" tool scheme. In this MCP Server, +your agent will write code against the TypeScript SDK, which will then be executed in an +isolated sandbox. To accomplish this, the server will expose two tools to your agent: -## Importing the tools and server individually +- The first tool is a docs search tool, which can be used to generically query for + documentation about your API/SDK. -```js -// Import the server, generated endpoints, or the init function -import { server, endpoints, init } from "beagle-mcp/server"; +- The second tool is a code tool, where the agent can write code against the TypeScript SDK. + The code will be executed in a sandbox environment without web or filesystem access. Then, + anything the code returns or prints will be returned to the agent as the result of the + tool call. -// import a specific tool -import retrievePlans from "beagle-mcp/tools/plans/retrieve-plans"; +Using this scheme, agents are capable of performing very complex tasks deterministically +and repeatably. -// initialize the server and all endpoints -init({ server, endpoints }); +## Running remotely -// manually start server -const transport = new StdioServerTransport(); -await server.connect(transport); +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. -// or initialize your own server with specific tools -const myServer = new McpServer(...); +Authorization can be provided via the following headers: +| Header | Equivalent client option | Security scheme | +| ----------- | ------------------------ | --------------- | +| `x-api-key` | `apiKey` | apiKey | -// 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!' }; - }) -}; +A configuration JSON for this server might look like this, assuming the server is hosted at `http://localhost:3000`: -// initialize the server with your custom endpoints -init({ server: myServer, endpoints: [retrievePlans, myCustomEndpoint] }); +```json +{ + "mcpServers": { + "corgi_tech_beagle_api": { + "url": "http://localhost:3000", + "headers": { + "x-api-key": "My API Key" + } + } + } +} ``` - -## Available Tools - -The following tools are available in this MCP server. - -### Resource `plans`: - -- `retrieve_plans` (`read`): retrieve a specific plans details by its code. -- `list_plans` (`read`): list all available plans, note this endpoint is currently unpaginated unlike all other list endpoints. - -### Resource `property_managers`: - -- `create_property_managers` (`write`): create a new property manager. -- `retrieve_property_managers` (`read`): get a property manager by id. -- `update_property_managers` (`write`): update an existing property manager by id, note that when updating contacts or addresses you need to send the whole array you want to replace them with. -- `list_property_managers` (`read`): list all property managers, note this endpoint is paginated. -- `delete_property_managers` (`write`): delete a property manager by id. - -### Resource `tenants`: - -- `create_tenants` (`write`): create a new tenant. -- `retrieve_tenants` (`read`): retrieve a single tenant by their id. -- `update_tenants` (`write`): update an existing tenant by their id. -- `list_tenants` (`read`): list all tenants, this endpoint is paginated and allows for queries by individual property manager. -- `delete_tenants` (`write`): delete an existing tenant by their id. - -### Resource `enrollments`: - -- `create_enrollments` (`write`): create a new enrollment for a tenant. -- `retrieve_enrollments` (`read`): get a specific enrollment by its id. -- `list_enrollments` (`read`): list all enrollments, this endpoint is paginated and allows for queries by individual property manager. -- `lapse_enrollments` (`write`): lapses a specific enrollment for a tenant, note that if a tenant has multiple enrollments (e.g., SDR and TLL), each must be lapsed individually - -### Resource `insurance_verification`: - -- `verify_insurance_verification` (`write`): trigger a job to parse a tenants insurance document(s) - -### Resource `webhook.endpoints`: - -- `create_webhook_endpoints` (`write`): creates a new webhook target. -- `retrieve_webhook_endpoints` (`read`): retrieve a single webhook endpoint by its id. -- `update_webhook_endpoints` (`write`): update an existing webhook endpoint by its id. -- `list_webhook_endpoints` (`read`): list all webhook endpoints, this endpoint is paginated and allows for queries by individual property manager. -- `delete_webhook_endpoints` (`write`): delete an existing webhook endpoint by its id. diff --git a/packages/mcp-server/build b/packages/mcp-server/build index c5a4e871..5dfe5145 100644 --- a/packages/mcp-server/build +++ b/packages/mcp-server/build @@ -19,7 +19,7 @@ done # 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 `beagle` dependency to point to NPM +# updates the `@corgi-tech/beagle` dependency to point to NPM node scripts/postprocess-dist-package-json.cjs # build to .js/.mjs/.d.ts files @@ -29,4 +29,28 @@ cp tsconfig.dist-src.json dist/src/tsconfig.json chmod +x dist/index.js -DIST_PATH=./dist PKG_IMPORT_PATH=beagle-mcp/ node ../../scripts/utils/postprocess-files.cjs +DIST_PATH=./dist PKG_IMPORT_PATH=@corgi-tech/beagle-mcp/ node ../../scripts/utils/postprocess-files.cjs + +# mcp bundle +rm -rf dist-bundle corgi_tech_beagle_api.mcpb; mkdir dist-bundle + +# copy package.json +PKG_JSON_PATH=../../packages/mcp-server/package.json node ../../scripts/utils/make-dist-package-json.cjs > dist-bundle/package.json + +# copy files +node scripts/copy-bundle-files.cjs + +# install runtime deps +cd dist-bundle +npm install +cd .. + +# pack bundle +cp manifest.json dist-bundle + +npx mcpb pack dist-bundle corgi_tech_beagle_api.mcpb + +npx mcpb sign corgi_tech_beagle_api.mcpb --self-signed + +# clean up +rm -rf dist-bundle diff --git a/packages/mcp-server/jest.config.ts b/packages/mcp-server/jest.config.ts index 1b4ac3c8..f213efaa 100644 --- a/packages/mcp-server/jest.config.ts +++ b/packages/mcp-server/jest.config.ts @@ -7,8 +7,8 @@ const config: JestConfigWithTsJest = { '^.+\\.(t|j)sx?$': ['@swc/jest', { sourceMaps: 'inline' }], }, moduleNameMapper: { - '^beagle-mcp$': '/src/index.ts', - '^beagle-mcp/(.*)$': '/src/$1', + '^@corgi-tech/beagle-mcp$': '/src/index.ts', + '^@corgi-tech/beagle-mcp/(.*)$': '/src/$1', }, modulePathIgnorePatterns: ['/dist/'], testPathIgnorePatterns: ['scripts'], diff --git a/packages/mcp-server/manifest.json b/packages/mcp-server/manifest.json new file mode 100644 index 00000000..2b467b9b --- /dev/null +++ b/packages/mcp-server/manifest.json @@ -0,0 +1,45 @@ +{ + "dxt_version": "0.2", + "name": "@corgi-tech/beagle-mcp", + "version": "2.0.0", + "description": "The official MCP Server for the Beagle API", + "author": { + "name": "Beagle" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/corgi-tech/beagle-sdks.git" + }, + "homepage": "https://github.com/corgi-tech/beagle-sdks/tree/main/packages/mcp-server#readme", + "server": { + "type": "node", + "entry_point": "index.js", + "mcp_config": { + "command": "node", + "args": [ + "${__dirname}/index.js" + ], + "env": { + "BEAGLE_API_KEY": "${user_config.BEAGLE_API_KEY}" + } + } + }, + "user_config": { + "BEAGLE_API_KEY": { + "title": "api_key", + "description": "", + "required": true, + "type": "string" + } + }, + "tools": [], + "tools_generated": true, + "compatibility": { + "runtimes": { + "node": ">=18.0.0" + } + }, + "keywords": [ + "api" + ] +} diff --git a/packages/mcp-server/package.json b/packages/mcp-server/package.json index 7c5896af..1ae62eb0 100644 --- a/packages/mcp-server/package.json +++ b/packages/mcp-server/package.json @@ -1,6 +1,6 @@ { - "name": "beagle-mcp", - "version": "0.0.1-alpha.0", + "name": "@corgi-tech/beagle-mcp", + "version": "2.0.0", "description": "The official MCP Server for the Beagle API", "author": "Beagle <>", "types": "dist/index.d.ts", @@ -8,13 +8,16 @@ "type": "commonjs", "repository": { "type": "git", - "url": "git+https://github.com/stainless-sdks/beagle-typescript.git", + "url": "git+https://github.com/corgi-tech/beagle-sdks.git", "directory": "packages/mcp-server" }, - "homepage": "https://github.com/stainless-sdks/beagle-typescript/tree/main/packages/mcp-server#readme", + "homepage": "https://github.com/corgi-tech/beagle-sdks/tree/main/packages/mcp-server#readme", "license": "Apache-2.0", "packageManager": "yarn@1.22.22", "private": false, + "publishConfig": { + "access": "public" + }, "scripts": { "test": "jest", "build": "bash ./build", @@ -23,39 +26,60 @@ "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 ." + "lint": "eslint .", + "fix": "eslint --fix ." }, "dependencies": { - "beagle": "file:../../dist/", - "@modelcontextprotocol/sdk": "^1.11.5", - "yargs": "^17.7.2", + "@corgi-tech/beagle": "link:../../dist/", + "ajv": "^8.18.0", "@cloudflare/cabidela": "^0.2.4", + "@hono/node-server": "^1.19.10", + "@modelcontextprotocol/sdk": "^1.27.1", + "hono": "^4.12.4", + "@valtown/deno-http-worker": "^0.0.21", + "cookie-parser": "^1.4.6", + "cors": "^2.8.5", + "express": "^5.1.0", + "fuse.js": "^7.1.0", + "minisearch": "^7.2.0", + "jq-web": "https://github.com/stainless-api/jq-web/releases/download/v0.8.8/jq-web.tar.gz", + "pino": "^10.3.1", + "pino-http": "^11.0.0", + "pino-pretty": "^13.1.3", + "qs": "^6.14.1", + "typescript": "5.8.3", + "yargs": "^17.7.2", "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": { + "@anthropic-ai/mcpb": "^2.1.2", + "@types/cookie-parser": "^1.4.10", + "@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", - "eslint": "^8.49.0", - "eslint-plugin-prettier": "^5.0.1", - "eslint-plugin-unused-imports": "^3.0.0", + "eslint": "^9.39.1", + "eslint-plugin-prettier": "^5.4.1", + "eslint-plugin-unused-imports": "^4.1.4", "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.8/tsc-multi.tgz", - "tsconfig-paths": "^4.0.0", - "typescript": "5.8.3" + "tsc-multi": "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.11/tsc-multi.tgz", + "tsconfig-paths": "^4.0.0" }, "imports": { - "beagle-mcp": ".", - "beagle-mcp/*": "./src/*" + "@corgi-tech/beagle-mcp": ".", + "@corgi-tech/beagle-mcp/*": "./src/*" }, "exports": { ".": { diff --git a/packages/mcp-server/scripts/copy-bundle-files.cjs b/packages/mcp-server/scripts/copy-bundle-files.cjs new file mode 100644 index 00000000..ac026dbd --- /dev/null +++ b/packages/mcp-server/scripts/copy-bundle-files.cjs @@ -0,0 +1,36 @@ +const fs = require('fs'); +const path = require('path'); +const pkgJson = require('../dist-bundle/package.json'); + +const distDir = path.resolve(__dirname, '..', 'dist'); +const distBundleDir = path.resolve(__dirname, '..', 'dist-bundle'); +const distBundlePkgJson = path.join(distBundleDir, 'package.json'); + +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 copyFiles() { + // copy runtime files + for await (const file of walk(distDir)) { + if (!/[cm]?js$/.test(file)) continue; + const dest = path.join(distBundleDir, path.relative(distDir, file)); + await fs.promises.mkdir(path.dirname(dest), { recursive: true }); + await fs.promises.copyFile(file, dest); + } + + // replace package.json reference with local reference + for (const dep in pkgJson.dependencies) { + if (dep === '@corgi-tech/beagle') { + pkgJson.dependencies[dep] = 'file:../../../dist/'; + } + } + + await fs.promises.writeFile(distBundlePkgJson, JSON.stringify(pkgJson, null, 2)); +} + +copyFiles(); diff --git a/packages/mcp-server/scripts/postprocess-dist-package-json.cjs b/packages/mcp-server/scripts/postprocess-dist-package-json.cjs index 9716d19b..b2c9fb38 100644 --- a/packages/mcp-server/scripts/postprocess-dist-package-json.cjs +++ b/packages/mcp-server/scripts/postprocess-dist-package-json.cjs @@ -4,7 +4,7 @@ const parentPkgJson = require('../../../package.json'); for (const dep in pkgJson.dependencies) { // ensure we point to NPM instead of a local directory - if (dep === 'beagle') { + if (dep === '@corgi-tech/beagle') { pkgJson.dependencies[dep] = '^' + parentPkgJson.version; } } diff --git a/packages/mcp-server/src/auth.ts b/packages/mcp-server/src/auth.ts new file mode 100644 index 00000000..f25e9eac --- /dev/null +++ b/packages/mcp-server/src/auth.ts @@ -0,0 +1,25 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { IncomingMessage } from 'node:http'; +import { ClientOptions } from '@corgi-tech/beagle'; +import { McpOptions } from './options'; + +export const parseClientAuthHeaders = (req: IncomingMessage, required?: boolean): Partial => { + const apiKey = + Array.isArray(req.headers['x-api-key']) ? req.headers['x-api-key'][0] : req.headers['x-api-key']; + return { apiKey }; +}; + +export const getStainlessApiKey = (req: IncomingMessage, mcpOptions: McpOptions): string | undefined => { + // Try to get the key from the x-stainless-api-key header + const headerKey = + Array.isArray(req.headers['x-stainless-api-key']) ? + req.headers['x-stainless-api-key'][0] + : req.headers['x-stainless-api-key']; + if (headerKey && typeof headerKey === 'string') { + return headerKey; + } + + // Fall back to value set in the mcpOptions (e.g. from environment variable), if provided + return mcpOptions.stainlessApiKey; +}; 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 00000000..78263e45 --- /dev/null +++ b/packages/mcp-server/src/code-tool-paths.cts @@ -0,0 +1,5 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export function getWorkerPath(): string { + return 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 00000000..ffbb8220 --- /dev/null +++ b/packages/mcp-server/src/code-tool-types.ts @@ -0,0 +1,17 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { ClientOptions } from '@corgi-tech/beagle'; + +export type WorkerInput = { + project_name: string; + code: string; + client_opts: ClientOptions; + intent?: string | undefined; +}; + +export type WorkerOutput = { + is_error: boolean; + result: unknown | null; + log_lines: string[]; + err_lines: string[]; +}; 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 00000000..fb2e9a40 --- /dev/null +++ b/packages/mcp-server/src/code-tool-worker.ts @@ -0,0 +1,297 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import path from 'node:path'; +import util from 'node:util'; +import Fuse from 'fuse.js'; +import ts from 'typescript'; +import { WorkerOutput } from './code-tool-types'; +import { Beagle, ClientOptions } from '@corgi-tech/beagle'; + +async function tseval(code: string) { + return import('data:application/typescript;charset=utf-8;base64,' + Buffer.from(code).toString('base64')); +} + +function getRunFunctionSource(code: string): { + type: 'declaration' | 'expression'; + client: string | undefined; + code: string; +} | null { + const sourceFile = ts.createSourceFile('code.ts', code, ts.ScriptTarget.Latest, true); + const printer = ts.createPrinter(); + + for (const statement of sourceFile.statements) { + // Check for top-level function declarations + if (ts.isFunctionDeclaration(statement)) { + if (statement.name?.text === 'run') { + return { + type: 'declaration', + client: statement.parameters[0]?.name.getText(), + code: printer.printNode(ts.EmitHint.Unspecified, statement.body!, sourceFile), + }; + } + } + + // Check for variable declarations: const run = () => {} or const run = function() {} + if (ts.isVariableStatement(statement)) { + for (const declaration of statement.declarationList.declarations) { + if ( + ts.isIdentifier(declaration.name) && + declaration.name.text === 'run' && + // Check if it's initialized with a function + declaration.initializer && + (ts.isFunctionExpression(declaration.initializer) || ts.isArrowFunction(declaration.initializer)) + ) { + return { + type: 'expression', + client: declaration.initializer.parameters[0]?.name.getText(), + code: printer.printNode(ts.EmitHint.Unspecified, declaration.initializer, sourceFile), + }; + } + } + } + } + + return null; +} + +function getTSDiagnostics(code: string): string[] { + const functionSource = getRunFunctionSource(code)!; + const codeWithImport = [ + 'import { Beagle } from "@corgi-tech/beagle";', + functionSource.type === 'declaration' ? + `async function run(${functionSource.client}: Beagle)` + : `const run: (${functionSource.client}: Beagle) => Promise =`, + functionSource.code, + ].join('\n'); + const sourcePath = path.resolve('code.ts'); + const ast = ts.createSourceFile(sourcePath, codeWithImport, ts.ScriptTarget.Latest, true); + const options = ts.getDefaultCompilerOptions(); + options.target = ts.ScriptTarget.Latest; + options.module = ts.ModuleKind.NodeNext; + options.moduleResolution = ts.ModuleResolutionKind.NodeNext; + const host = ts.createCompilerHost(options, true); + const newHost: typeof host = { + ...host, + getSourceFile: (...args) => { + if (path.resolve(args[0]) === sourcePath) { + return ast; + } + return host.getSourceFile(...args); + }, + readFile: (...args) => { + if (path.resolve(args[0]) === sourcePath) { + return codeWithImport; + } + return host.readFile(...args); + }, + fileExists: (...args) => { + if (path.resolve(args[0]) === sourcePath) { + return true; + } + return host.fileExists(...args); + }, + }; + const program = ts.createProgram({ + options, + rootNames: [sourcePath], + host: newHost, + }); + const diagnostics = ts.getPreEmitDiagnostics(program, ast); + return diagnostics.map((d) => { + const message = ts.flattenDiagnosticMessageText(d.messageText, '\n'); + if (!d.file || !d.start) return `- ${message}`; + const { line: lineNumber } = ts.getLineAndCharacterOfPosition(d.file, d.start); + const line = codeWithImport.split('\n').at(lineNumber)?.trim(); + return line ? `- ${message}\n ${line}` : `- ${message}`; + }); +} + +const fuse = new Fuse( + [ + 'client.plans.list', + 'client.plans.retrieve', + 'client.propertyManagers.create', + 'client.propertyManagers.delete', + 'client.propertyManagers.list', + 'client.propertyManagers.retrieve', + 'client.propertyManagers.update', + 'client.tenants.create', + 'client.tenants.delete', + 'client.tenants.list', + 'client.tenants.retrieve', + 'client.tenants.update', + 'client.enrollments.create', + 'client.enrollments.lapse', + 'client.enrollments.list', + 'client.enrollments.retrieve', + 'client.enrollments.retrieveCertificate', + 'client.insuranceVerification.verify', + ], + { threshold: 1, shouldSort: true }, +); + +function getMethodSuggestions(fullyQualifiedMethodName: string): string[] { + return fuse + .search(fullyQualifiedMethodName) + .map(({ item }) => item) + .slice(0, 5); +} + +const proxyToObj = new WeakMap(); +const objToProxy = new WeakMap(); + +type ClientProxyConfig = { + path: string[]; + isBelievedBad?: boolean; +}; + +function makeSdkProxy(obj: T, { path, isBelievedBad = false }: ClientProxyConfig): T { + let proxy: T = objToProxy.get(obj); + + if (!proxy) { + proxy = new Proxy(obj, { + get(target, prop, receiver) { + const propPath = [...path, String(prop)]; + const value = Reflect.get(target, prop, receiver); + + if (isBelievedBad || (!(prop in target) && value === undefined)) { + // If we're accessing a path that doesn't exist, it will probably eventually error. + // Let's proxy it and mark it bad so that we can control the error message. + // We proxy an empty class so that an invocation or construction attempt is possible. + return makeSdkProxy(class {}, { path: propPath, isBelievedBad: true }); + } + + if (value !== null && (typeof value === 'object' || typeof value === 'function')) { + return makeSdkProxy(value, { path: propPath, isBelievedBad }); + } + + return value; + }, + + apply(target, thisArg, args) { + if (isBelievedBad || typeof target !== 'function') { + const fullyQualifiedMethodName = path.join('.'); + const suggestions = getMethodSuggestions(fullyQualifiedMethodName); + throw new Error( + `${fullyQualifiedMethodName} is not a function. Did you mean: ${suggestions.join(', ')}`, + ); + } + + return Reflect.apply(target, proxyToObj.get(thisArg) ?? thisArg, args); + }, + + construct(target, args, newTarget) { + if (isBelievedBad || typeof target !== 'function') { + const fullyQualifiedMethodName = path.join('.'); + const suggestions = getMethodSuggestions(fullyQualifiedMethodName); + throw new Error( + `${fullyQualifiedMethodName} is not a constructor. Did you mean: ${suggestions.join(', ')}`, + ); + } + + return Reflect.construct(target, args, newTarget); + }, + }); + + objToProxy.set(obj, proxy); + proxyToObj.set(proxy, obj); + } + + return proxy; +} + +function parseError(code: string, error: unknown): string | undefined { + if (!(error instanceof Error)) return; + const cause = error.cause instanceof Error ? `: ${error.cause.message}` : ''; + const message = error.name ? `${error.name}: ${error.message}${cause}` : `${error.message}${cause}`; + try { + // Deno uses V8; the first ":LINE:COLUMN" is the top of stack. + const lineNumber = error.stack?.match(/:([0-9]+):[0-9]+/)?.[1]; + // -1 for the zero-based indexing + const line = + lineNumber && + code + .split('\n') + .at(parseInt(lineNumber, 10) - 1) + ?.trim(); + return line ? `${message}\n at line ${lineNumber}\n ${line}` : message; + } catch { + return message; + } +} + +const fetch = async (req: Request): Promise => { + const { opts, code } = (await req.json()) as { opts: ClientOptions; code: string }; + + const runFunctionSource = code ? getRunFunctionSource(code) : null; + if (!runFunctionSource) { + const message = + code ? + 'The code is missing a top-level `run` function.' + : 'The code argument is missing. Provide one containing a top-level `run` function.'; + return Response.json( + { + is_error: true, + result: `${message} Write code within this template:\n\n\`\`\`\nasync function run(client) {\n // Fill this out\n}\n\`\`\``, + log_lines: [], + err_lines: [], + } satisfies WorkerOutput, + { status: 400, statusText: 'Code execution error' }, + ); + } + + const diagnostics = getTSDiagnostics(code); + if (diagnostics.length > 0) { + return Response.json( + { + is_error: true, + result: `The code contains TypeScript diagnostics:\n${diagnostics.join('\n')}`, + log_lines: [], + err_lines: [], + } satisfies WorkerOutput, + { status: 400, statusText: 'Code execution error' }, + ); + } + + const client = new Beagle({ + ...opts, + }); + + const log_lines: string[] = []; + const err_lines: string[] = []; + const originalConsole = globalThis.console; + globalThis.console = { + ...originalConsole, + log: (...args: unknown[]) => { + log_lines.push(util.format(...args)); + }, + error: (...args: unknown[]) => { + err_lines.push(util.format(...args)); + }, + }; + try { + let run_ = async (client: any) => {}; + run_ = (await tseval(`${code}\nexport default run;`)).default; + const result = await run_(makeSdkProxy(client, { path: ['client'] })); + return Response.json({ + is_error: false, + result, + log_lines, + err_lines, + } satisfies WorkerOutput); + } catch (e) { + return Response.json( + { + is_error: true, + result: parseError(code, e), + log_lines, + err_lines, + } satisfies WorkerOutput, + { status: 400, statusText: 'Code execution error' }, + ); + } finally { + globalThis.console = originalConsole; + } +}; + +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 00000000..86e7a56c --- /dev/null +++ b/packages/mcp-server/src/code-tool.ts @@ -0,0 +1,395 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { + ContentBlock, + McpRequestContext, + McpTool, + Metadata, + ToolCallResult, + asErrorResult, + asTextContentResult, +} from './types'; +import { Tool } from '@modelcontextprotocol/sdk/types.js'; +import { readEnv, requireValue } from './util'; +import { WorkerInput, WorkerOutput } from './code-tool-types'; +import { getLogger } from './logger'; +import { SdkMethod } from './methods'; +import { McpCodeExecutionMode } from './options'; +import { ClientOptions } from '@corgi-tech/beagle'; + +const prompt = `Runs JavaScript code to interact with the Beagle API. + +You are a skilled TypeScript programmer writing code to interface with the service. +Define an async function named "run" that takes a single parameter of an initialized SDK client and it will be run. +For example: + +\`\`\` +async function run(client) { + const plans = await client.plans.list(); + + console.log(plans.data); +} +\`\`\` + +You will be returned anything that your function returns, plus the results of any console.log statements. +Do not add try-catch blocks for single API calls. The tool will handle errors for you. +Do not add comments unless necessary for generating better code. +Code will run in a container, and cannot interact with the network outside of the given SDK client. +Variables will not persist between calls, so make sure to return or log any data you might need later. +Remember that you are writing TypeScript code, so you need to be careful with your types. +Always type dynamic key-value stores explicitly as Record instead of {}.`; + +/** + * A tool that runs code against a copy of the SDK. + * + * Instead of exposing every endpoint as its 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 blockedMethods - The methods to block for code execution. Blocking is done by simple string + * matching, so it is not secure against obfuscation. For stronger security, block in the downstream API + * with limited API keys. + * @param codeExecutionMode - Whether to execute code in a local Deno environment or in a remote + * sandbox environment hosted by Stainless. + */ +export function codeTool({ + blockedMethods, + codeExecutionMode, +}: { + blockedMethods: SdkMethod[] | undefined; + codeExecutionMode: McpCodeExecutionMode; +}): McpTool { + const metadata: Metadata = { resource: 'all', operation: 'write', tags: [] }; + const tool: Tool = { + name: 'execute', + description: prompt, + inputSchema: { + type: 'object', + properties: { + code: { + type: 'string', + description: 'Code to execute.', + }, + intent: { + type: 'string', + description: 'Task you are trying to perform. Used for improving the service.', + }, + }, + required: ['code'], + }, + }; + + const logger = getLogger(); + + const handler = async ({ + reqContext, + args, + }: { + reqContext: McpRequestContext; + args: any; + }): Promise => { + const code = args.code as string; + // Do very basic blocking of code that includes forbidden method names. + // + // WARNING: This is not secure against obfuscation and other evasion methods. If + // stronger security blocks are required, then these should be enforced in the downstream + // API (e.g., by having users call the MCP server with API keys with limited permissions). + if (blockedMethods) { + const blockedMatches = blockedMethods.filter((method) => code.includes(method.fullyQualifiedName)); + if (blockedMatches.length > 0) { + return asErrorResult( + `The following methods have been blocked by the MCP server and cannot be used in code execution: ${blockedMatches + .map((m) => m.fullyQualifiedName) + .join(', ')}`, + ); + } + } + + let result: ToolCallResult; + const startTime = Date.now(); + + if (codeExecutionMode === 'local') { + logger.debug('Executing code in local Deno environment'); + result = await localDenoHandler({ reqContext, args }); + } else { + logger.debug('Executing code in remote Stainless environment'); + result = await remoteStainlessHandler({ reqContext, args }); + } + + logger.info( + { + codeExecutionMode, + durationMs: Date.now() - startTime, + isError: result.isError, + contentRows: result.content?.length ?? 0, + }, + 'Got code tool execution result', + ); + return result; + }; + + return { metadata, tool, handler }; +} + +const remoteStainlessHandler = async ({ + reqContext, + args, +}: { + reqContext: McpRequestContext; + args: any; +}): Promise => { + const code = args.code as string; + const intent = args.intent as string | undefined; + const client = reqContext.client; + + const codeModeEndpoint = readEnv('CODE_MODE_ENDPOINT_URL') ?? 'https://api.stainless.com/api/ai/code-tool'; + + const localClientEnvs = { + BEAGLE_API_KEY: requireValue( + readEnv('BEAGLE_API_KEY') ?? client.apiKey, + 'set BEAGLE_API_KEY environment variable or provide apiKey client option', + ), + BEAGLE_BASE_URL: + readEnv('BEAGLE_BASE_URL') ?? readEnv('BEAGLE_ENVIRONMENT') ? undefined : client.baseURL ?? undefined, + }; + // Merge any upstream client envs from the request header, with upstream values taking precedence. + const mergedClientEnvs = { ...localClientEnvs, ...reqContext.upstreamClientEnvs }; + + // Setting a Stainless API key authenticates requests to the code tool endpoint. + const res = await fetch(codeModeEndpoint, { + method: 'POST', + headers: { + ...(reqContext.stainlessApiKey && { Authorization: reqContext.stainlessApiKey }), + 'Content-Type': 'application/json', + 'x-stainless-mcp-client-envs': JSON.stringify(mergedClientEnvs), + }, + body: JSON.stringify({ + project_name: 'beagle', + code, + intent, + client_opts: { environment: (readEnv('BEAGLE_ENVIRONMENT') || undefined) as any }, + } satisfies WorkerInput), + }); + + if (!res.ok) { + if (res.status === 404 && !reqContext.stainlessApiKey) { + throw new Error( + 'Could not access code tool for this project. You may need to provide a Stainless API key via the STAINLESS_API_KEY environment variable, the --stainless-api-key flag, or the x-stainless-api-key HTTP header.', + ); + } + throw new Error( + `${res.status}: ${ + res.statusText + } error when trying to contact Code Tool server. Details: ${await res.text()}`, + ); + } + + const { is_error, result, log_lines, err_lines } = (await res.json()) as WorkerOutput; + const hasLogs = log_lines.length > 0 || err_lines.length > 0; + const output = { + result, + ...(log_lines.length > 0 && { log_lines }), + ...(err_lines.length > 0 && { err_lines }), + }; + if (is_error) { + return asErrorResult(typeof result === 'string' && !hasLogs ? result : JSON.stringify(output, null, 2)); + } + return asTextContentResult(output); +}; + +const localDenoHandler = async ({ + reqContext, + args, +}: { + reqContext: McpRequestContext; + args: unknown; +}): Promise => { + const fs = await import('node:fs'); + const path = await import('node:path'); + const url = await import('node:url'); + const { newDenoHTTPWorker } = await import('@valtown/deno-http-worker'); + const { getWorkerPath } = await import('./code-tool-paths.cjs'); + const workerPath = getWorkerPath(); + + const client = reqContext.client; + const baseURLHostname = new URL(client.baseURL).hostname; + const { code } = args as { code: string }; + + let denoPath: string; + + const packageRoot = path.resolve(path.dirname(workerPath), '..'); + const packageNodeModulesPath = path.resolve(packageRoot, 'node_modules'); + + // Check if deno is in PATH + const { execSync } = await import('node:child_process'); + try { + execSync('command -v deno', { stdio: 'ignore' }); + denoPath = 'deno'; + } catch { + try { + // Use deno binary in node_modules if it's found + const denoNodeModulesPath = path.resolve(packageNodeModulesPath, 'deno', 'bin.cjs'); + await fs.promises.access(denoNodeModulesPath, fs.constants.X_OK); + denoPath = denoNodeModulesPath; + } catch { + return asErrorResult( + 'Deno is required for code execution but was not found. ' + + 'Install it from https://deno.land or run: npm install deno', + ); + } + } + + const allowReadPaths = [ + 'code-tool-worker.mjs', + `${workerPath.replace(/([\/\\]node_modules)[\/\\].+$/, '$1')}/`, + packageRoot, + ]; + + // Follow symlinks in node_modules to allow read access to workspace-linked packages + try { + const sdkPkgName = '@corgi-tech/beagle'; + const sdkDir = path.resolve(packageNodeModulesPath, sdkPkgName); + const realSdkDir = fs.realpathSync(sdkDir); + if (realSdkDir !== sdkDir) { + allowReadPaths.push(realSdkDir); + } + } catch { + // Ignore if symlink resolution fails + } + + const allowRead = allowReadPaths.join(','); + + const worker = await newDenoHTTPWorker(url.pathToFileURL(workerPath), { + denoExecutable: denoPath, + runFlags: [ + `--node-modules-dir=manual`, + `--allow-read=${allowRead}`, + `--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: path.dirname(workerPath), + // Merge any upstream client envs into the Deno subprocess environment, + // with the upstream env vars taking precedence. + env: { ...process.env, ...reqContext.upstreamClientEnvs }, + }, + }); + + try { + const resp = await new Promise((resolve, reject) => { + worker.addEventListener('exit', (exitCode) => { + reject(new Error(`Worker exited with code ${exitCode}`)); + }); + + // Strip null/undefined values so that the worker SDK client can fall back to + // reading from environment variables (including any upstreamClientEnvs). + const opts = { + ...(client.baseURL != null ? { baseURL: client.baseURL } : undefined), + ...(client.apiKey != null ? { apiKey: client.apiKey } : undefined), + defaultHeaders: { + 'X-Stainless-MCP': 'true', + }, + } satisfies Partial as ClientOptions; + + 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, + }); + + req.write(body, (err) => { + if (err != null) { + reject(err); + } + }); + + req.end(); + }); + + if (resp.status === 200) { + const { result, log_lines, err_lines } = (await resp.json()) as WorkerOutput; + const returnOutput: ContentBlock | null = + result == null ? null : ( + { + type: 'text', + text: typeof result === 'string' ? result : JSON.stringify(result), + } + ); + const logOutput: ContentBlock | null = + log_lines.length === 0 ? + null + : { + type: 'text', + text: log_lines.join('\n'), + }; + const errOutput: ContentBlock | null = + err_lines.length === 0 ? + null + : { + type: 'text', + text: 'Error output:\n' + err_lines.join('\n'), + }; + return { + content: [returnOutput, logOutput, errOutput].filter((block) => block !== null), + }; + } else { + const { result, log_lines, err_lines } = (await resp.json()) as WorkerOutput; + const messageOutput: ContentBlock | null = + result == null ? null : ( + { + type: 'text', + text: typeof result === 'string' ? result : JSON.stringify(result), + } + ); + const logOutput: ContentBlock | null = + log_lines.length === 0 ? + null + : { + type: 'text', + text: log_lines.join('\n'), + }; + const errOutput: ContentBlock | null = + err_lines.length === 0 ? + null + : { + type: 'text', + text: 'Error output:\n' + err_lines.join('\n'), + }; + return { + content: [messageOutput, logOutput, errOutput].filter((block) => block !== null), + isError: true, + }; + } + } finally { + worker.terminate(); + } +}; diff --git a/packages/mcp-server/src/compat.ts b/packages/mcp-server/src/compat.ts deleted file mode 100644 index ff0d6d40..00000000 --- a/packages/mcp-server/src/compat.ts +++ /dev/null @@ -1,478 +0,0 @@ -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, -}; - -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 - */ -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, - visited: Set = new Set(), -): 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 && !visited.has(schema.$ref)) { - usedDefs[defName] = def; - visited.add(schema.$ref); - Object.assign(usedDefs, findUsedDefs(def, defs, visited)); - visited.delete(schema.$ref); - } - } - 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, 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. - */ -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/docs-search-tool.ts b/packages/mcp-server/src/docs-search-tool.ts new file mode 100644 index 00000000..73325b7d --- /dev/null +++ b/packages/mcp-server/src/docs-search-tool.ts @@ -0,0 +1,138 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { Tool } from '@modelcontextprotocol/sdk/types.js'; +import { Metadata, McpRequestContext, asTextContentResult } from './types'; +import { getLogger } from './logger'; +import type { LocalDocsSearch } from './local-docs-search'; + +export const metadata: Metadata = { + resource: 'all', + operation: 'read', + tags: [], + httpMethod: 'get', +}; + +export const tool: Tool = { + name: 'search_docs', + description: + 'Search SDK documentation to find methods, parameters, and usage examples for interacting with the API. Use this before writing code when you need to discover the right approach.', + inputSchema: { + type: 'object', + properties: { + query: { + type: 'string', + description: 'The query to search for.', + }, + language: { + type: 'string', + description: 'The language for the SDK to search for.', + enum: ['http', 'python', 'go', 'typescript', 'javascript', 'terraform', 'ruby', 'java', 'kotlin'], + }, + detail: { + type: 'string', + description: 'The amount of detail to return.', + enum: ['default', 'verbose'], + }, + }, + required: ['query', 'language'], + }, + annotations: { + readOnlyHint: true, + }, +}; + +const docsSearchURL = + process.env['DOCS_SEARCH_URL'] || 'https://api.stainless.com/api/projects/beagle/docs/search'; + +let _localSearch: LocalDocsSearch | undefined; + +export function setLocalSearch(search: LocalDocsSearch): void { + _localSearch = search; +} + +async function searchLocal(args: Record): Promise { + if (!_localSearch) { + throw new Error('Local search not initialized'); + } + + const query = (args['query'] as string) ?? ''; + const language = (args['language'] as string) ?? 'typescript'; + const detail = (args['detail'] as string) ?? 'default'; + + return _localSearch.search({ + query, + language, + detail, + maxResults: 10, + }).results; +} + +async function searchRemote(args: Record, reqContext: McpRequestContext): Promise { + const body = args as any; + const query = new URLSearchParams(body).toString(); + + const startTime = Date.now(); + const result = await fetch(`${docsSearchURL}?${query}`, { + headers: { + ...(reqContext.stainlessApiKey && { Authorization: reqContext.stainlessApiKey }), + ...(reqContext.mcpSessionId && { 'x-stainless-mcp-session-id': reqContext.mcpSessionId }), + ...(reqContext.mcpClientInfo && { + 'x-stainless-mcp-client-info': JSON.stringify(reqContext.mcpClientInfo), + }), + }, + }); + + const logger = getLogger(); + + if (!result.ok) { + const errorText = await result.text(); + logger.warn( + { + durationMs: Date.now() - startTime, + query: body.query, + status: result.status, + statusText: result.statusText, + errorText, + }, + 'Got error response from docs search tool', + ); + + if (result.status === 404 && !reqContext.stainlessApiKey) { + throw new Error( + 'Could not find docs for this project. You may need to provide a Stainless API key via the STAINLESS_API_KEY environment variable, the --stainless-api-key flag, or the x-stainless-api-key HTTP header.', + ); + } + + throw new Error( + `${result.status}: ${result.statusText} when using doc search tool. Details: ${errorText}`, + ); + } + + const resultBody = await result.json(); + logger.info( + { + durationMs: Date.now() - startTime, + query: body.query, + }, + 'Got docs search result', + ); + return resultBody; +} + +export const handler = async ({ + reqContext, + args, +}: { + reqContext: McpRequestContext; + args: Record | undefined; +}) => { + const body = args ?? {}; + + if (_localSearch) { + return asTextContentResult(await searchLocal(body)); + } + + return asTextContentResult(await searchRemote(body, reqContext)); +}; + +export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/dynamic-tools.ts b/packages/mcp-server/src/dynamic-tools.ts deleted file mode 100644 index 1657a5f3..00000000 --- a/packages/mcp-server/src/dynamic-tools.ts +++ /dev/null @@ -1,153 +0,0 @@ -import Beagle from 'beagle'; -import { Endpoint, asTextContentResult, ToolCallResult } from './tools/types'; -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 Beagle TypeScript API', - inputSchema: zodToInputSchema(listEndpointsSchema), - }, - handler: async (client: Beagle, args: Record | undefined): Promise => { - const query = args && listEndpointsSchema.parse(args).search_query?.trim(); - - const filteredEndpoints = - query && query.length > 0 ? - 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 && field.toLowerCase().includes(query.toLowerCase())); - }) - : endpoints; - - return asTextContentResult({ - 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 Beagle 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: Beagle, 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 asTextContentResult(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 Beagle 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: Beagle, args: Record | undefined): Promise => { - 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 await endpoint.handler(client, endpointArgs); - }, - }; - - return [getEndpointTool, listEndpointsTool, invokeEndpointTool]; -} diff --git a/packages/mcp-server/src/http.ts b/packages/mcp-server/src/http.ts new file mode 100644 index 00000000..d3ea8db1 --- /dev/null +++ b/packages/mcp-server/src/http.ts @@ -0,0 +1,227 @@ +// 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'; +import { ClientOptions } from '@corgi-tech/beagle'; +import express from 'express'; +import pino from 'pino'; +import pinoHttp from 'pino-http'; +import { getStainlessApiKey, parseClientAuthHeaders } from './auth'; +import { getLogger } from './logger'; +import { McpOptions } from './options'; +import { initMcpServer, newMcpServer } from './server'; + +const newServer = async ({ + clientOptions, + mcpOptions, + req, + res, +}: { + clientOptions: ClientOptions; + mcpOptions: McpOptions; + req: express.Request; + res: express.Response; +}): Promise => { + const stainlessApiKey = getStainlessApiKey(req, mcpOptions); + const customInstructionsPath = mcpOptions.customInstructionsPath; + const server = await newMcpServer({ stainlessApiKey, customInstructionsPath }); + + const authOptions = parseClientAuthHeaders(req, false); + + let upstreamClientEnvs: Record | undefined; + const clientEnvsHeader = req.headers['x-stainless-mcp-client-envs']; + if (typeof clientEnvsHeader === 'string') { + try { + const parsed = JSON.parse(clientEnvsHeader); + if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) { + upstreamClientEnvs = parsed; + } + } catch { + // Ignore malformed header + } + } + + // Parse x-stainless-mcp-client-permissions header to override permission options + // + // Note: Permissions are best-effort and intended to prevent clients from doing unexpected things; + // they're not a hard security boundary, so we allow arbitrary, client-driven overrides. + // + // See the Stainless MCP documentation for more details. + let effectiveMcpOptions = mcpOptions; + const clientPermissionsHeader = req.headers['x-stainless-mcp-client-permissions']; + if (typeof clientPermissionsHeader === 'string') { + try { + const parsed = JSON.parse(clientPermissionsHeader); + if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) { + effectiveMcpOptions = { + ...mcpOptions, + ...(typeof parsed.allow_http_gets === 'boolean' && { codeAllowHttpGets: parsed.allow_http_gets }), + ...(Array.isArray(parsed.allowed_methods) && { codeAllowedMethods: parsed.allowed_methods }), + ...(Array.isArray(parsed.blocked_methods) && { codeBlockedMethods: parsed.blocked_methods }), + }; + getLogger().info( + { clientPermissions: parsed }, + 'Overriding code execution permissions from x-stainless-mcp-client-permissions header', + ); + } + } catch (error) { + getLogger().warn({ error }, 'Failed to parse x-stainless-mcp-client-permissions header'); + } + } + + const mcpClientInfo = + typeof req.body?.params?.clientInfo?.name === 'string' ? + { name: req.body.params.clientInfo.name, version: String(req.body.params.clientInfo.version ?? '') } + : undefined; + + await initMcpServer({ + server: server, + mcpOptions: effectiveMcpOptions, + clientOptions: { + ...clientOptions, + ...authOptions, + }, + stainlessApiKey: stainlessApiKey, + upstreamClientEnvs, + mcpSessionId: (req as any).mcpSessionId, + mcpClientInfo, + }); + + if (mcpClientInfo) { + getLogger().info({ mcpSessionId: (req as any).mcpSessionId, mcpClientInfo }, 'MCP client connected'); + } + + return server; +}; + +const post = + (options: { clientOptions: ClientOptions; mcpOptions: McpOptions }) => + async (req: express.Request, res: express.Response) => { + const server = await newServer({ ...options, req, res }); + // If we return null, we already set the authorization error. + if (server === null) return; + const transport = new StreamableHTTPServerTransport(); + await server.connect(transport as any); + 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', + }, + }); +}; + +const redactHeaders = (headers: Record) => { + const hiddenHeaders = /auth|cookie|key|token|x-stainless-mcp-client-envs/i; + const filtered = { ...headers }; + Object.keys(filtered).forEach((key) => { + if (hiddenHeaders.test(key)) { + filtered[key] = '[REDACTED]'; + } + }); + return filtered; +}; + +export const streamableHTTPApp = ({ + clientOptions = {}, + mcpOptions, +}: { + clientOptions?: ClientOptions; + mcpOptions: McpOptions; +}): express.Express => { + const app = express(); + app.set('query parser', 'extended'); + app.use(express.json()); + app.use((req: express.Request, res: express.Response, next: express.NextFunction) => { + const existing = req.headers['mcp-session-id']; + const sessionId = (Array.isArray(existing) ? existing[0] : existing) || crypto.randomUUID(); + (req as any).mcpSessionId = sessionId; + const origWriteHead = res.writeHead.bind(res); + res.writeHead = function (statusCode: number, ...rest: any[]) { + res.setHeader('mcp-session-id', sessionId); + return origWriteHead(statusCode, ...rest); + } as typeof res.writeHead; + next(); + }); + app.use( + pinoHttp({ + logger: getLogger(), + customProps: (req) => ({ + mcpSessionId: (req as any).mcpSessionId, + }), + customLogLevel: (req, res) => { + if (res.statusCode >= 500) { + return 'error'; + } else if (res.statusCode >= 400) { + return 'warn'; + } + return 'info'; + }, + customSuccessMessage: function (req, res) { + return `Request ${req.method} to ${req.url} completed with status ${res.statusCode}`; + }, + customErrorMessage: function (req, res, err) { + return `Request ${req.method} to ${req.url} errored with status ${res.statusCode}`; + }, + serializers: { + req: pino.stdSerializers.wrapRequestSerializer((req) => { + return { + ...req, + headers: redactHeaders(req.raw.headers), + }; + }), + res: pino.stdSerializers.wrapResponseSerializer((res) => { + return { + ...res, + headers: redactHeaders(res.headers), + }; + }), + }, + }), + ); + + app.get('/health', async (req: express.Request, res: express.Response) => { + res.status(200).send('OK'); + }); + app.get('/', get); + app.post('/', post({ clientOptions, mcpOptions })); + app.delete('/', del); + + return app; +}; + +export const launchStreamableHTTPServer = async ({ + mcpOptions, + port, +}: { + mcpOptions: McpOptions; + port: number | string | undefined; +}) => { + const app = streamableHTTPApp({ mcpOptions }); + const server = app.listen(port); + const address = server.address(); + + const logger = getLogger(); + + if (typeof address === 'string') { + logger.info(`MCP Server running on streamable HTTP at ${address}`); + } else if (address !== null) { + logger.info(`MCP Server running on streamable HTTP on port ${address.port}`); + } else { + logger.info(`MCP Server running on streamable HTTP on port ${port}`); + } +}; diff --git a/packages/mcp-server/src/index.ts b/packages/mcp-server/src/index.ts index 06213572..5bca4a60 100644 --- a/packages/mcp-server/src/index.ts +++ b/packages/mcp-server/src/index.ts @@ -1,104 +1,67 @@ #!/usr/bin/env node -import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; -import { init, selectTools, server } from './server'; -import { Endpoint, endpoints } from './tools'; -import { McpOptions, parseOptions } from './options'; +import { selectTools } from './server'; +import { McpOptions, parseCLIOptions } from './options'; +import { launchStdioServer } from './stdio'; +import { launchStreamableHTTPServer } from './http'; +import type { McpTool } from './types'; +import { configureLogger, getLogger } from './logger'; async function main() { const options = parseOptionsOrError(); + configureLogger({ + level: options.debug ? 'debug' : 'info', + pretty: options.logFormat === 'pretty', + }); - if (options.list) { - listAllTools(); - return; - } - - const includedTools = selectToolsOrError(endpoints, options); + const selectedTools = await selectToolsOrError(options); - console.error( - `MCP Server starting with ${includedTools.length} tools:`, - includedTools.map((e) => e.tool.name), + getLogger().info( + { tools: selectedTools.map((e) => e.tool.name) }, + `MCP Server starting with ${selectedTools.length} tools`, ); - 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); + break; + case 'http': + await launchStreamableHTTPServer({ + mcpOptions: options, + port: options.socket ?? options.port, + }); + break; + } } if (require.main === module) { main().catch((error) => { - console.error('Fatal error in main():', error); + // Logger might not be initialized yet + console.error('Fatal error in main()', error); process.exit(1); }); } function parseOptionsOrError() { try { - return parseOptions(); + return parseCLIOptions(); } catch (error) { - console.error('Error parsing options:', error); + // Logger is initialized after options, so use console.error here + console.error('Error parsing options', error); process.exit(1); } } -function selectToolsOrError(endpoints: Endpoint[], options: McpOptions) { +async function selectToolsOrError(options: McpOptions): Promise { try { - const includedTools = selectTools(endpoints, options); + const includedTools = selectTools(options); if (includedTools.length === 0) { - console.error('No tools match the provided filters.'); + getLogger().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); - } + getLogger().error({ error }, 'Error filtering tools'); 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/instructions.ts b/packages/mcp-server/src/instructions.ts new file mode 100644 index 00000000..ef0b6936 --- /dev/null +++ b/packages/mcp-server/src/instructions.ts @@ -0,0 +1,83 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import fs from 'fs/promises'; +import { getLogger } from './logger'; +import { readEnv } from './util'; + +const INSTRUCTIONS_CACHE_TTL_MS = 15 * 60 * 1000; // 15 minutes + +interface InstructionsCacheEntry { + fetchedInstructions: string; + fetchedAt: number; +} + +const instructionsCache = new Map(); + +export async function getInstructions({ + stainlessApiKey, + customInstructionsPath, +}: { + stainlessApiKey?: string | undefined; + customInstructionsPath?: string | undefined; +}): Promise { + const now = Date.now(); + const cacheKey = customInstructionsPath ?? stainlessApiKey ?? ''; + const cached = instructionsCache.get(cacheKey); + + if (cached && now - cached.fetchedAt <= INSTRUCTIONS_CACHE_TTL_MS) { + return cached.fetchedInstructions; + } + + // Evict stale entries so the cache doesn't grow unboundedly. + for (const [key, entry] of instructionsCache) { + if (now - entry.fetchedAt > INSTRUCTIONS_CACHE_TTL_MS) { + instructionsCache.delete(key); + } + } + + let fetchedInstructions: string; + + if (customInstructionsPath) { + fetchedInstructions = await fetchLatestInstructionsFromFile(customInstructionsPath); + } else { + fetchedInstructions = await fetchLatestInstructionsFromApi(stainlessApiKey); + } + + instructionsCache.set(cacheKey, { fetchedInstructions, fetchedAt: now }); + return fetchedInstructions; +} + +async function fetchLatestInstructionsFromFile(path: string): Promise { + try { + return await fs.readFile(path, 'utf-8'); + } catch (error) { + getLogger().error({ error, path }, 'Error fetching instructions from file'); + throw error; + } +} + +async function fetchLatestInstructionsFromApi(stainlessApiKey: string | undefined): Promise { + // Setting the stainless API key is optional, but may be required + // to authenticate requests to the Stainless API. + const response = await fetch( + readEnv('CODE_MODE_INSTRUCTIONS_URL') ?? 'https://api.stainless.com/api/ai/instructions/beagle', + { + method: 'GET', + headers: { ...(stainlessApiKey && { Authorization: stainlessApiKey }) }, + }, + ); + + let instructions: string | undefined; + if (!response.ok) { + getLogger().warn( + 'Warning: failed to retrieve MCP server instructions. Proceeding with default instructions...', + ); + + instructions = + '\n This is the beagle MCP server.\n\n Available tools:\n - search_docs: Search SDK documentation to find the right methods and parameters.\n - execute: Run TypeScript code against a pre-authenticated SDK client. Define an async run(client) function.\n\n Workflow:\n - If unsure about the API, call search_docs first.\n - Write complete solutions in a single execute call when possible. For large datasets, use API filters to narrow results or paginate within a single execute block.\n - If execute returns an error, read the error and fix your code rather than retrying the same approach.\n - Variables do not persist between execute calls. Return or log all data you need.\n - Individual HTTP requests to the API have a 30-second timeout. If a request times out, try a smaller query or add filters.\n - Code execution has a total timeout of approximately 5 minutes. If your code times out, simplify it or break it into smaller steps.\n '; + } + + instructions ??= ((await response.json()) as { instructions: string }).instructions; + + return instructions; +} diff --git a/packages/mcp-server/src/local-docs-search.ts b/packages/mcp-server/src/local-docs-search.ts new file mode 100644 index 00000000..19fc8b30 --- /dev/null +++ b/packages/mcp-server/src/local-docs-search.ts @@ -0,0 +1,1293 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import MiniSearch from 'minisearch'; +import * as fs from 'node:fs/promises'; +import * as path from 'node:path'; +import { getLogger } from './logger'; + +type PerLanguageData = { + method?: string; + example?: string; +}; + +type MethodEntry = { + name: string; + endpoint: string; + httpMethod: string; + summary: string; + description: string; + stainlessPath: string; + qualified: string; + params?: string[]; + response?: string; + markdown?: string; + perLanguage?: Record; +}; + +type ProseChunk = { + content: string; + tag: string; + sectionContext?: string; + source?: string; +}; + +type MiniSearchDocument = { + id: string; + kind: 'http_method' | 'prose'; + name?: string; + endpoint?: string; + summary?: string; + description?: string; + qualified?: string; + stainlessPath?: string; + content?: string; + sectionContext?: string; + _original: Record; +}; + +type SearchResult = { + results: (string | Record)[]; +}; + +const EMBEDDED_METHODS: MethodEntry[] = [ + { + name: 'list', + endpoint: '/api/plans', + httpMethod: 'get', + summary: 'List Plans', + description: + "List all insurance plans available to your API key. Plan availability, coverage details, and pricing can vary by client configuration. Use the plan's name/code when creating enrollments.", + stainlessPath: '(resource) plans > (method) list', + qualified: 'client.plans.list', + response: + '{ data: { description: string; name: string; rate: number; contents?: number; liability?: number; rentBandMax?: number; rentBandMin?: number; termMonths?: number; value?: number; }[]; success: true; }', + markdown: + "## list\n\n`client.plans.list(): { data: plan[]; success: true; }`\n\n**get** `/api/plans`\n\nList all insurance plans available to your API key. Plan availability, coverage details, and pricing can vary by client configuration. Use the plan's name/code when creating enrollments.\n\n### Returns\n\n- `{ data: { description: string; name: string; rate: number; contents?: number; liability?: number; rentBandMax?: number; rentBandMin?: number; termMonths?: number; value?: number; }[]; success: true; }`\n\n - `data: { description: string; name: string; rate: number; contents?: number; liability?: number; rentBandMax?: number; rentBandMin?: number; termMonths?: number; value?: number; }[]`\n - `success: true`\n\n### Example\n\n```typescript\nimport Beagle from '@corgi-tech/beagle';\n\nconst client = new Beagle();\n\nconst plans = await client.plans.list();\n\nconsole.log(plans);\n```", + perLanguage: { + typescript: { + method: 'client.plans.list', + example: + "import Beagle from '@corgi-tech/beagle';\n\nconst client = new Beagle({\n apiKey: process.env['BEAGLE_API_KEY'], // This is the default and can be omitted\n});\n\nconst plans = await client.plans.list();\n\nconsole.log(plans.data);", + }, + python: { + method: 'plans.list', + example: + 'import os\nfrom beagle import Beagle\n\nclient = Beagle(\n api_key=os.environ.get("BEAGLE_API_KEY"), # This is the default and can be omitted\n)\nplans = client.plans.list()\nprint(plans.data)', + }, + java: { + method: 'plans().list', + example: + 'package com.beagle.api.example;\n\nimport com.beagle.api.client.BeagleClient;\nimport com.beagle.api.client.okhttp.BeagleOkHttpClient;\nimport com.beagle.api.models.plans.PlanListParams;\nimport com.beagle.api.models.plans.PlanListResponse;\n\npublic final class Main {\n private Main() {}\n\n public static void main(String[] args) {\n BeagleClient client = BeagleOkHttpClient.fromEnv();\n\n PlanListResponse plans = client.plans().list();\n }\n}', + }, + go: { + method: 'client.Plans.List', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/beagle-go"\n\t"github.com/stainless-sdks/beagle-go/option"\n)\n\nfunc main() {\n\tclient := beagle.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tplans, err := client.Plans.List(context.TODO())\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", plans.Data)\n}\n', + }, + ruby: { + method: 'plans.list', + example: + 'require "beagle"\n\nbeagle = Beagle::Client.new(\n api_key: "My API Key",\n environment: "staging" # defaults to "production"\n)\n\nplans = beagle.plans.list\n\nputs(plans)', + }, + csharp: { + method: 'Plans.List', + example: + 'PlanListParams parameters = new();\n\nvar plans = await client.Plans.List(parameters);\n\nConsole.WriteLine(plans);', + }, + http: { + example: 'curl https://developer.beagleforpm.com/api/plans \\\n -H "x-api-key: $BEAGLE_API_KEY"', + }, + }, + }, + { + name: 'retrieve', + endpoint: '/api/plans/{code}', + httpMethod: 'get', + summary: 'Get Plan', + description: + "Retrieve a specific plan's details by its code. Plans are only returned when they are available to your API key, and pricing can vary by client configuration.", + stainlessPath: '(resource) plans > (method) retrieve', + qualified: 'client.plans.retrieve', + params: ['code: string;'], + response: + '{ data: { description: string; name: string; rate: number; contents?: number; liability?: number; rentBandMax?: number; rentBandMin?: number; termMonths?: number; value?: number; }; success: true; }', + markdown: + "## retrieve\n\n`client.plans.retrieve(code: string): { data: plan; success: true; }`\n\n**get** `/api/plans/{code}`\n\nRetrieve a specific plan's details by its code. Plans are only returned when they are available to your API key, and pricing can vary by client configuration.\n\n### Parameters\n\n- `code: string`\n\n### Returns\n\n- `{ data: { description: string; name: string; rate: number; contents?: number; liability?: number; rentBandMax?: number; rentBandMin?: number; termMonths?: number; value?: number; }; success: true; }`\n\n - `data: { description: string; name: string; rate: number; contents?: number; liability?: number; rentBandMax?: number; rentBandMin?: number; termMonths?: number; value?: number; }`\n - `success: true`\n\n### Example\n\n```typescript\nimport Beagle from '@corgi-tech/beagle';\n\nconst client = new Beagle();\n\nconst plan = await client.plans.retrieve('code');\n\nconsole.log(plan);\n```", + perLanguage: { + typescript: { + method: 'client.plans.retrieve', + example: + "import Beagle from '@corgi-tech/beagle';\n\nconst client = new Beagle({\n apiKey: process.env['BEAGLE_API_KEY'], // This is the default and can be omitted\n});\n\nconst plan = await client.plans.retrieve('code');\n\nconsole.log(plan.data);", + }, + python: { + method: 'plans.retrieve', + example: + 'import os\nfrom beagle import Beagle\n\nclient = Beagle(\n api_key=os.environ.get("BEAGLE_API_KEY"), # This is the default and can be omitted\n)\nplan = client.plans.retrieve(\n "code",\n)\nprint(plan.data)', + }, + java: { + method: 'plans().retrieve', + example: + 'package com.beagle.api.example;\n\nimport com.beagle.api.client.BeagleClient;\nimport com.beagle.api.client.okhttp.BeagleOkHttpClient;\nimport com.beagle.api.models.plans.PlanRetrieveParams;\nimport com.beagle.api.models.plans.PlanRetrieveResponse;\n\npublic final class Main {\n private Main() {}\n\n public static void main(String[] args) {\n BeagleClient client = BeagleOkHttpClient.fromEnv();\n\n PlanRetrieveResponse plan = client.plans().retrieve("code");\n }\n}', + }, + go: { + method: 'client.Plans.Get', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/beagle-go"\n\t"github.com/stainless-sdks/beagle-go/option"\n)\n\nfunc main() {\n\tclient := beagle.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tplan, err := client.Plans.Get(context.TODO(), "code")\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", plan.Data)\n}\n', + }, + ruby: { + method: 'plans.retrieve', + example: + 'require "beagle"\n\nbeagle = Beagle::Client.new(\n api_key: "My API Key",\n environment: "staging" # defaults to "production"\n)\n\nplan = beagle.plans.retrieve("code")\n\nputs(plan)', + }, + csharp: { + method: 'Plans.Retrieve', + example: + 'PlanRetrieveParams parameters = new() { Code = "code" };\n\nvar plan = await client.Plans.Retrieve(parameters);\n\nConsole.WriteLine(plan);', + }, + http: { + example: + 'curl https://developer.beagleforpm.com/api/plans/$CODE \\\n -H "x-api-key: $BEAGLE_API_KEY"', + }, + }, + }, + { + name: 'retrieve', + endpoint: '/api/property-managers/{id}', + httpMethod: 'get', + summary: 'Get Property Manager', + description: 'get a property manager by id.', + stainlessPath: '(resource) property_managers > (method) retrieve', + qualified: 'client.propertyManagers.retrieve', + params: ['id: number;'], + response: + '{ data: { id: number; addresses: address[]; contacts: contact[]; name: string; clickWrapAt?: number; totalUnits?: number; }; success: true; }', + markdown: + "## retrieve\n\n`client.propertyManagers.retrieve(id: number): { data: property_manager; success: true; }`\n\n**get** `/api/property-managers/{id}`\n\nget a property manager by id.\n\n### Parameters\n\n- `id: number`\n\n### Returns\n\n- `{ data: { id: number; addresses: address[]; contacts: contact[]; name: string; clickWrapAt?: number; totalUnits?: number; }; success: true; }`\n\n - `data: { id: number; addresses: { city: string; state: string; street1: string; zip: string; street2?: string; }[]; contacts: { email: string; name: object; phone?: string; }[]; name: string; clickWrapAt?: number; totalUnits?: number; }`\n - `success: true`\n\n### Example\n\n```typescript\nimport Beagle from '@corgi-tech/beagle';\n\nconst client = new Beagle();\n\nconst propertyManager = await client.propertyManagers.retrieve(123);\n\nconsole.log(propertyManager);\n```", + perLanguage: { + typescript: { + method: 'client.propertyManagers.retrieve', + example: + "import Beagle from '@corgi-tech/beagle';\n\nconst client = new Beagle({\n apiKey: process.env['BEAGLE_API_KEY'], // This is the default and can be omitted\n});\n\nconst propertyManager = await client.propertyManagers.retrieve(123);\n\nconsole.log(propertyManager.data);", + }, + python: { + method: 'property_managers.retrieve', + example: + 'import os\nfrom beagle import Beagle\n\nclient = Beagle(\n api_key=os.environ.get("BEAGLE_API_KEY"), # This is the default and can be omitted\n)\nproperty_manager = client.property_managers.retrieve(\n 123,\n)\nprint(property_manager.data)', + }, + java: { + method: 'propertyManagers().retrieve', + example: + 'package com.beagle.api.example;\n\nimport com.beagle.api.client.BeagleClient;\nimport com.beagle.api.client.okhttp.BeagleOkHttpClient;\nimport com.beagle.api.models.propertymanagers.PropertyManagerRetrieveParams;\nimport com.beagle.api.models.propertymanagers.PropertyManagerRetrieveResponse;\n\npublic final class Main {\n private Main() {}\n\n public static void main(String[] args) {\n BeagleClient client = BeagleOkHttpClient.fromEnv();\n\n PropertyManagerRetrieveResponse propertyManager = client.propertyManagers().retrieve(123.0);\n }\n}', + }, + go: { + method: 'client.PropertyManagers.Get', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/beagle-go"\n\t"github.com/stainless-sdks/beagle-go/option"\n)\n\nfunc main() {\n\tclient := beagle.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tpropertyManager, err := client.PropertyManagers.Get(context.TODO(), 123)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", propertyManager.Data)\n}\n', + }, + ruby: { + method: 'property_managers.retrieve', + example: + 'require "beagle"\n\nbeagle = Beagle::Client.new(\n api_key: "My API Key",\n environment: "staging" # defaults to "production"\n)\n\nproperty_manager = beagle.property_managers.retrieve(123)\n\nputs(property_manager)', + }, + csharp: { + method: 'PropertyManagers.Retrieve', + example: + 'PropertyManagerRetrieveParams parameters = new() { ID = 123 };\n\nvar propertyManager = await client.PropertyManagers.Retrieve(parameters);\n\nConsole.WriteLine(propertyManager);', + }, + http: { + example: + 'curl https://developer.beagleforpm.com/api/property-managers/$ID \\\n -H "x-api-key: $BEAGLE_API_KEY"', + }, + }, + }, + { + name: 'update', + endpoint: '/api/property-managers/{id}', + httpMethod: 'patch', + summary: 'Update Property Manager', + description: + 'update an existing property manager by ID\n\n(Note that when updating **contacts** or **addresses** you need to send the whole array you want to replace them with)', + stainlessPath: '(resource) property_managers > (method) update', + qualified: 'client.propertyManagers.update', + params: [ + 'id: number;', + 'addresses?: { city: string; state: string; street1: string; zip: string; street2?: string; }[];', + 'clickWrapAt?: number;', + 'contacts?: { email: string; name: { first: string; last: string; }; phone?: string; }[];', + 'name?: string;', + 'totalUnits?: number;', + ], + response: + '{ data: { id: number; addresses: address[]; contacts: contact[]; name: string; clickWrapAt?: number; totalUnits?: number; }; success: true; }', + markdown: + "## update\n\n`client.propertyManagers.update(id: number, addresses?: { city: string; state: string; street1: string; zip: string; street2?: string; }[], clickWrapAt?: number, contacts?: { email: string; name: object; phone?: string; }[], name?: string, totalUnits?: number): { data: property_manager; success: true; }`\n\n**patch** `/api/property-managers/{id}`\n\nupdate an existing property manager by ID\n\n(Note that when updating **contacts** or **addresses** you need to send the whole array you want to replace them with)\n\n### Parameters\n\n- `id: number`\n\n- `addresses?: { city: string; state: string; street1: string; zip: string; street2?: string; }[]`\n street addresses for each Property\n\n- `clickWrapAt?: number`\n unix timestamp (ms) of clickwrap agreement signature\n\n- `contacts?: { email: string; name: { first: string; last: string; }; phone?: string; }[]`\n contact information for each Property Manager\n\n- `name?: string`\n name of the Property Management Company\n\n- `totalUnits?: number`\n total number of units managed by this property manager\n\n### Returns\n\n- `{ data: { id: number; addresses: address[]; contacts: contact[]; name: string; clickWrapAt?: number; totalUnits?: number; }; success: true; }`\n\n - `data: { id: number; addresses: { city: string; state: string; street1: string; zip: string; street2?: string; }[]; contacts: { email: string; name: object; phone?: string; }[]; name: string; clickWrapAt?: number; totalUnits?: number; }`\n - `success: true`\n\n### Example\n\n```typescript\nimport Beagle from '@corgi-tech/beagle';\n\nconst client = new Beagle();\n\nconst propertyManager = await client.propertyManagers.update(123);\n\nconsole.log(propertyManager);\n```", + perLanguage: { + typescript: { + method: 'client.propertyManagers.update', + example: + "import Beagle from '@corgi-tech/beagle';\n\nconst client = new Beagle({\n apiKey: process.env['BEAGLE_API_KEY'], // This is the default and can be omitted\n});\n\nconst propertyManager = await client.propertyManagers.update(123);\n\nconsole.log(propertyManager.data);", + }, + python: { + method: 'property_managers.update', + example: + 'import os\nfrom beagle import Beagle\n\nclient = Beagle(\n api_key=os.environ.get("BEAGLE_API_KEY"), # This is the default and can be omitted\n)\nproperty_manager = client.property_managers.update(\n id=123,\n)\nprint(property_manager.data)', + }, + java: { + method: 'propertyManagers().update', + example: + 'package com.beagle.api.example;\n\nimport com.beagle.api.client.BeagleClient;\nimport com.beagle.api.client.okhttp.BeagleOkHttpClient;\nimport com.beagle.api.models.propertymanagers.PropertyManagerUpdateParams;\nimport com.beagle.api.models.propertymanagers.PropertyManagerUpdateResponse;\n\npublic final class Main {\n private Main() {}\n\n public static void main(String[] args) {\n BeagleClient client = BeagleOkHttpClient.fromEnv();\n\n PropertyManagerUpdateResponse propertyManager = client.propertyManagers().update(123.0);\n }\n}', + }, + go: { + method: 'client.PropertyManagers.Update', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/beagle-go"\n\t"github.com/stainless-sdks/beagle-go/option"\n)\n\nfunc main() {\n\tclient := beagle.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tpropertyManager, err := client.PropertyManagers.Update(\n\t\tcontext.TODO(),\n\t\t123,\n\t\tbeagle.PropertyManagerUpdateParams{},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", propertyManager.Data)\n}\n', + }, + ruby: { + method: 'property_managers.update', + example: + 'require "beagle"\n\nbeagle = Beagle::Client.new(\n api_key: "My API Key",\n environment: "staging" # defaults to "production"\n)\n\nproperty_manager = beagle.property_managers.update(123)\n\nputs(property_manager)', + }, + csharp: { + method: 'PropertyManagers.Update', + example: + 'PropertyManagerUpdateParams parameters = new() { ID = 123 };\n\nvar propertyManager = await client.PropertyManagers.Update(parameters);\n\nConsole.WriteLine(propertyManager);', + }, + http: { + example: + 'curl https://developer.beagleforpm.com/api/property-managers/$ID \\\n -X PATCH \\\n -H \'Content-Type: application/json\' \\\n -H "x-api-key: $BEAGLE_API_KEY" \\\n -d \'{\n "addresses": [\n {\n "city": "South Salt Lake",\n "state": "UT",\n "street1": "123 Electric Ave.",\n "zip": "84115",\n "kind": "place of business"\n }\n ],\n "clickWrapAt": 1773359774000,\n "contacts": [\n {\n "email": "mr.milchick@example.com",\n "name": {\n "first": "Seth",\n "last": "Milchick"\n },\n "phone": "(123) 456-7890",\n "kind": "reporting"\n }\n ],\n "name": "Lumon Apartments"\n }\'', + }, + }, + }, + { + name: 'delete', + endpoint: '/api/property-managers/{id}', + httpMethod: 'delete', + summary: 'Delete Property Manager', + description: 'delete a property manager by ID.', + stainlessPath: '(resource) property_managers > (method) delete', + qualified: 'client.propertyManagers.delete', + params: ['id: number;'], + markdown: + "## delete\n\n`client.propertyManagers.delete(id: number): void`\n\n**delete** `/api/property-managers/{id}`\n\ndelete a property manager by ID.\n\n### Parameters\n\n- `id: number`\n\n### Example\n\n```typescript\nimport Beagle from '@corgi-tech/beagle';\n\nconst client = new Beagle();\n\nawait client.propertyManagers.delete(123)\n```", + perLanguage: { + typescript: { + method: 'client.propertyManagers.delete', + example: + "import Beagle from '@corgi-tech/beagle';\n\nconst client = new Beagle({\n apiKey: process.env['BEAGLE_API_KEY'], // This is the default and can be omitted\n});\n\nawait client.propertyManagers.delete(123);", + }, + python: { + method: 'property_managers.delete', + example: + 'import os\nfrom beagle import Beagle\n\nclient = Beagle(\n api_key=os.environ.get("BEAGLE_API_KEY"), # This is the default and can be omitted\n)\nclient.property_managers.delete(\n 123,\n)', + }, + java: { + method: 'propertyManagers().delete', + example: + 'package com.beagle.api.example;\n\nimport com.beagle.api.client.BeagleClient;\nimport com.beagle.api.client.okhttp.BeagleOkHttpClient;\nimport com.beagle.api.models.propertymanagers.PropertyManagerDeleteParams;\n\npublic final class Main {\n private Main() {}\n\n public static void main(String[] args) {\n BeagleClient client = BeagleOkHttpClient.fromEnv();\n\n client.propertyManagers().delete(123.0);\n }\n}', + }, + go: { + method: 'client.PropertyManagers.Delete', + example: + 'package main\n\nimport (\n\t"context"\n\n\t"github.com/stainless-sdks/beagle-go"\n\t"github.com/stainless-sdks/beagle-go/option"\n)\n\nfunc main() {\n\tclient := beagle.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\terr := client.PropertyManagers.Delete(context.TODO(), 123)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n}\n', + }, + ruby: { + method: 'property_managers.delete', + example: + 'require "beagle"\n\nbeagle = Beagle::Client.new(\n api_key: "My API Key",\n environment: "staging" # defaults to "production"\n)\n\nresult = beagle.property_managers.delete(123)\n\nputs(result)', + }, + csharp: { + method: 'PropertyManagers.Delete', + example: + 'PropertyManagerDeleteParams parameters = new() { ID = 123 };\n\nawait client.PropertyManagers.Delete(parameters);', + }, + http: { + example: + 'curl https://developer.beagleforpm.com/api/property-managers/$ID \\\n -X DELETE \\\n -H "x-api-key: $BEAGLE_API_KEY"', + }, + }, + }, + { + name: 'list', + endpoint: '/api/property-managers', + httpMethod: 'get', + summary: 'List Property Managers', + description: 'list all property managers, note this endpoint is paginated.', + stainlessPath: '(resource) property_managers > (method) list', + qualified: 'client.propertyManagers.list', + params: ['page?: number;', 'size?: number;'], + response: '{ data: { items: object[]; pagination: object; }; success: true; }', + markdown: + "## list\n\n`client.propertyManagers.list(page?: number, size?: number): { data: object; success: true; }`\n\n**get** `/api/property-managers`\n\nlist all property managers, note this endpoint is paginated.\n\n### Parameters\n\n- `page?: number`\n Page number to fetch.\n\n- `size?: number`\n Number of items per page.\n\n### Returns\n\n- `{ data: { items: object[]; pagination: object; }; success: true; }`\n\n - `data: { items: { id: number; addresses: object[]; contacts: object[]; name: string; clickWrapAt?: number; totalUnits?: number; }[]; pagination: { page: number; pages: number; records: number; size: number; }; }`\n - `success: true`\n\n### Example\n\n```typescript\nimport Beagle from '@corgi-tech/beagle';\n\nconst client = new Beagle();\n\nconst propertyManagers = await client.propertyManagers.list();\n\nconsole.log(propertyManagers);\n```", + perLanguage: { + typescript: { + method: 'client.propertyManagers.list', + example: + "import Beagle from '@corgi-tech/beagle';\n\nconst client = new Beagle({\n apiKey: process.env['BEAGLE_API_KEY'], // This is the default and can be omitted\n});\n\nconst propertyManagers = await client.propertyManagers.list();\n\nconsole.log(propertyManagers.data);", + }, + python: { + method: 'property_managers.list', + example: + 'import os\nfrom beagle import Beagle\n\nclient = Beagle(\n api_key=os.environ.get("BEAGLE_API_KEY"), # This is the default and can be omitted\n)\nproperty_managers = client.property_managers.list()\nprint(property_managers.data)', + }, + java: { + method: 'propertyManagers().list', + example: + 'package com.beagle.api.example;\n\nimport com.beagle.api.client.BeagleClient;\nimport com.beagle.api.client.okhttp.BeagleOkHttpClient;\nimport com.beagle.api.models.propertymanagers.PropertyManagerListParams;\nimport com.beagle.api.models.propertymanagers.PropertyManagerListResponse;\n\npublic final class Main {\n private Main() {}\n\n public static void main(String[] args) {\n BeagleClient client = BeagleOkHttpClient.fromEnv();\n\n PropertyManagerListResponse propertyManagers = client.propertyManagers().list();\n }\n}', + }, + go: { + method: 'client.PropertyManagers.List', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/beagle-go"\n\t"github.com/stainless-sdks/beagle-go/option"\n)\n\nfunc main() {\n\tclient := beagle.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tpropertyManagers, err := client.PropertyManagers.List(context.TODO(), beagle.PropertyManagerListParams{})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", propertyManagers.Data)\n}\n', + }, + ruby: { + method: 'property_managers.list', + example: + 'require "beagle"\n\nbeagle = Beagle::Client.new(\n api_key: "My API Key",\n environment: "staging" # defaults to "production"\n)\n\nproperty_managers = beagle.property_managers.list\n\nputs(property_managers)', + }, + csharp: { + method: 'PropertyManagers.List', + example: + 'PropertyManagerListParams parameters = new();\n\nvar propertyManagers = await client.PropertyManagers.List(parameters);\n\nConsole.WriteLine(propertyManagers);', + }, + http: { + example: + 'curl https://developer.beagleforpm.com/api/property-managers \\\n -H "x-api-key: $BEAGLE_API_KEY"', + }, + }, + }, + { + name: 'create', + endpoint: '/api/property-managers', + httpMethod: 'post', + summary: 'Create Property Manager', + description: 'create a new property manager.', + stainlessPath: '(resource) property_managers > (method) create', + qualified: 'client.propertyManagers.create', + params: [ + 'addresses: { city: string; state: string; street1: string; zip: string; street2?: string; }[];', + 'contacts: { email: string; name: { first: string; last: string; }; phone?: string; }[];', + 'name: string;', + 'clickWrapAt?: number;', + 'totalUnits?: number;', + ], + response: + '{ data: { id: number; addresses: address[]; contacts: contact[]; name: string; clickWrapAt?: number; totalUnits?: number; }; success: true; }', + markdown: + "## create\n\n`client.propertyManagers.create(addresses: { city: string; state: string; street1: string; zip: string; street2?: string; }[], contacts: { email: string; name: object; phone?: string; }[], name: string, clickWrapAt?: number, totalUnits?: number): { data: property_manager; success: true; }`\n\n**post** `/api/property-managers`\n\ncreate a new property manager.\n\n### Parameters\n\n- `addresses: { city: string; state: string; street1: string; zip: string; street2?: string; }[]`\n street addresses for each Property\n\n- `contacts: { email: string; name: { first: string; last: string; }; phone?: string; }[]`\n contact information for each Property Manager\n\n- `name: string`\n name of the Property Management Company\n\n- `clickWrapAt?: number`\n unix timestamp (ms) of clickwrap agreement signature\n\n- `totalUnits?: number`\n total number of units managed by this property manager\n\n### Returns\n\n- `{ data: { id: number; addresses: address[]; contacts: contact[]; name: string; clickWrapAt?: number; totalUnits?: number; }; success: true; }`\n\n - `data: { id: number; addresses: { city: string; state: string; street1: string; zip: string; street2?: string; }[]; contacts: { email: string; name: object; phone?: string; }[]; name: string; clickWrapAt?: number; totalUnits?: number; }`\n - `success: true`\n\n### Example\n\n```typescript\nimport Beagle from '@corgi-tech/beagle';\n\nconst client = new Beagle();\n\nconst propertyManager = await client.propertyManagers.create({\n addresses: [{\n city: 'South Salt Lake',\n state: 'UT',\n street1: '123 Electric Ave.',\n zip: '84115',\n kind: 'place of business',\n}],\n contacts: [{\n email: 'mr.milchick@example.com',\n name: { first: 'Seth', last: 'Milchick' },\n kind: 'reporting',\n}],\n name: 'Lumon Apartments',\n});\n\nconsole.log(propertyManager);\n```", + perLanguage: { + typescript: { + method: 'client.propertyManagers.create', + example: + "import Beagle from '@corgi-tech/beagle';\n\nconst client = new Beagle({\n apiKey: process.env['BEAGLE_API_KEY'], // This is the default and can be omitted\n});\n\nconst propertyManager = await client.propertyManagers.create({\n addresses: [\n {\n city: 'South Salt Lake',\n state: 'UT',\n street1: '123 Electric Ave.',\n zip: '84115',\n kind: 'place of business',\n },\n ],\n contacts: [\n {\n email: 'mr.milchick@example.com',\n name: { first: 'Seth', last: 'Milchick' },\n kind: 'reporting',\n },\n ],\n name: 'Lumon Apartments',\n});\n\nconsole.log(propertyManager.data);", + }, + python: { + method: 'property_managers.create', + example: + 'import os\nfrom beagle import Beagle\n\nclient = Beagle(\n api_key=os.environ.get("BEAGLE_API_KEY"), # This is the default and can be omitted\n)\nproperty_manager = client.property_managers.create(\n addresses=[{\n "city": "South Salt Lake",\n "state": "UT",\n "street1": "123 Electric Ave.",\n "zip": "84115",\n "kind": "place of business",\n }],\n contacts=[{\n "email": "mr.milchick@example.com",\n "name": {\n "first": "Seth",\n "last": "Milchick",\n },\n "kind": "reporting",\n }],\n name="Lumon Apartments",\n)\nprint(property_manager.data)', + }, + java: { + method: 'propertyManagers().create', + example: + 'package com.beagle.api.example;\n\nimport com.beagle.api.client.BeagleClient;\nimport com.beagle.api.client.okhttp.BeagleOkHttpClient;\nimport com.beagle.api.models.propertymanagers.PropertyManagerCreateParams;\nimport com.beagle.api.models.propertymanagers.PropertyManagerCreateResponse;\nimport com.beagle.api.models.tenants.Contact;\n\npublic final class Main {\n private Main() {}\n\n public static void main(String[] args) {\n BeagleClient client = BeagleOkHttpClient.fromEnv();\n\n PropertyManagerCreateParams params = PropertyManagerCreateParams.builder()\n .addAddress(PropertyManagerCreateParams.Address.builder()\n .city("South Salt Lake")\n .state("UT")\n .street1("123 Electric Ave.")\n .zip("84115")\n .kind(PropertyManagerCreateParams.Address.Kind.PLACE_OF_BUSINESS)\n .build())\n .addContact(PropertyManagerCreateParams.Contact.builder()\n .email("mr.milchick@example.com")\n .name(Contact.Name.builder()\n .first("Seth")\n .last("Milchick")\n .build())\n .kind(PropertyManagerCreateParams.Contact.Kind.REPORTING)\n .build())\n .name("Lumon Apartments")\n .build();\n PropertyManagerCreateResponse propertyManager = client.propertyManagers().create(params);\n }\n}', + }, + go: { + method: 'client.PropertyManagers.New', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/beagle-go"\n\t"github.com/stainless-sdks/beagle-go/option"\n)\n\nfunc main() {\n\tclient := beagle.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tpropertyManager, err := client.PropertyManagers.New(context.TODO(), beagle.PropertyManagerNewParams{\n\t\tAddresses: []beagle.PropertyManagerNewParamsAddress{{\n\t\t\tAddressParam: beagle.AddressParam{\n\t\t\t\tCity: "South Salt Lake",\n\t\t\t\tState: "UT",\n\t\t\t\tStreet1: "123 Electric Ave.",\n\t\t\t\tZip: "84115",\n\t\t\t},\n\t\t\tKind: "place of business",\n\t\t}},\n\t\tContacts: []beagle.PropertyManagerNewParamsContact{{\n\t\t\tContactParam: beagle.ContactParam{\n\t\t\t\tEmail: "mr.milchick@example.com",\n\t\t\t\tName: beagle.ContactNameParam{\n\t\t\t\t\tFirst: "Seth",\n\t\t\t\t\tLast: "Milchick",\n\t\t\t\t},\n\t\t\t},\n\t\t\tKind: "reporting",\n\t\t}},\n\t\tName: "Lumon Apartments",\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", propertyManager.Data)\n}\n', + }, + ruby: { + method: 'property_managers.create', + example: + 'require "beagle"\n\nbeagle = Beagle::Client.new(\n api_key: "My API Key",\n environment: "staging" # defaults to "production"\n)\n\nproperty_manager = beagle.property_managers.create(\n addresses: [\n {city: "South Salt Lake", state: "UT", street1: "123 Electric Ave.", zip: "84115", kind: :"place of business"}\n ],\n contacts: [{email: "mr.milchick@example.com", name: {first: "Seth", last: "Milchick"}, kind: :reporting}],\n name: "Lumon Apartments"\n)\n\nputs(property_manager)', + }, + csharp: { + method: 'PropertyManagers.Create', + example: + 'PropertyManagerCreateParams parameters = new()\n{\n Addresses =\n [\n new()\n {\n City = "South Salt Lake",\n State = "UT",\n Street1 = "123 Electric Ave.",\n Zip = "84115",\n Street2 = "street2",\n Kind = Kind.PlaceOfBusiness,\n },\n ],\n Contacts =\n [\n new()\n {\n Email = "mr.milchick@example.com",\n Name = new()\n {\n First = "Seth",\n Last = "Milchick",\n },\n Phone = "(123) 456-7890",\n Kind = Kind.Reporting,\n },\n ],\n Name = "Lumon Apartments",\n};\n\nvar propertyManager = await client.PropertyManagers.Create(parameters);\n\nConsole.WriteLine(propertyManager);', + }, + http: { + example: + 'curl https://developer.beagleforpm.com/api/property-managers \\\n -H \'Content-Type: application/json\' \\\n -H "x-api-key: $BEAGLE_API_KEY" \\\n -d \'{\n "addresses": [\n {\n "city": "South Salt Lake",\n "state": "UT",\n "street1": "123 Electric Ave.",\n "zip": "84115",\n "kind": "place of business"\n }\n ],\n "contacts": [\n {\n "email": "mr.milchick@example.com",\n "name": {\n "first": "Seth",\n "last": "Milchick"\n },\n "phone": "(123) 456-7890",\n "kind": "reporting"\n }\n ],\n "name": "Lumon Apartments",\n "clickWrapAt": 1773359774000\n }\'', + }, + }, + }, + { + name: 'retrieve', + endpoint: '/api/tenants/{id}', + httpMethod: 'get', + summary: 'Get Tenant', + description: 'retrieve a single tenant by their id.', + stainlessPath: '(resource) tenants > (method) retrieve', + qualified: 'client.tenants.retrieve', + params: ['id: number;'], + response: + '{ data: { id: number; address: address; contact: contact; expectedMoveInDate?: string; expectedMoveOutDate?: string; }; success: true; }', + markdown: + "## retrieve\n\n`client.tenants.retrieve(id: number): { data: tenant; success: true; }`\n\n**get** `/api/tenants/{id}`\n\nretrieve a single tenant by their id.\n\n### Parameters\n\n- `id: number`\n\n### Returns\n\n- `{ data: { id: number; address: address; contact: contact; expectedMoveInDate?: string; expectedMoveOutDate?: string; }; success: true; }`\n\n - `data: { id: number; address: { city: string; state: string; street1: string; zip: string; street2?: string; }; contact: { email: string; name: object; phone?: string; }; expectedMoveInDate?: string; expectedMoveOutDate?: string; }`\n - `success: true`\n\n### Example\n\n```typescript\nimport Beagle from '@corgi-tech/beagle';\n\nconst client = new Beagle();\n\nconst tenant = await client.tenants.retrieve(123);\n\nconsole.log(tenant);\n```", + perLanguage: { + typescript: { + method: 'client.tenants.retrieve', + example: + "import Beagle from '@corgi-tech/beagle';\n\nconst client = new Beagle({\n apiKey: process.env['BEAGLE_API_KEY'], // This is the default and can be omitted\n});\n\nconst tenant = await client.tenants.retrieve(123);\n\nconsole.log(tenant.data);", + }, + python: { + method: 'tenants.retrieve', + example: + 'import os\nfrom beagle import Beagle\n\nclient = Beagle(\n api_key=os.environ.get("BEAGLE_API_KEY"), # This is the default and can be omitted\n)\ntenant = client.tenants.retrieve(\n 123,\n)\nprint(tenant.data)', + }, + java: { + method: 'tenants().retrieve', + example: + 'package com.beagle.api.example;\n\nimport com.beagle.api.client.BeagleClient;\nimport com.beagle.api.client.okhttp.BeagleOkHttpClient;\nimport com.beagle.api.models.tenants.TenantRetrieveParams;\nimport com.beagle.api.models.tenants.TenantRetrieveResponse;\n\npublic final class Main {\n private Main() {}\n\n public static void main(String[] args) {\n BeagleClient client = BeagleOkHttpClient.fromEnv();\n\n TenantRetrieveResponse tenant = client.tenants().retrieve(123.0);\n }\n}', + }, + go: { + method: 'client.Tenants.Get', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/beagle-go"\n\t"github.com/stainless-sdks/beagle-go/option"\n)\n\nfunc main() {\n\tclient := beagle.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\ttenant, err := client.Tenants.Get(context.TODO(), 123)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", tenant.Data)\n}\n', + }, + ruby: { + method: 'tenants.retrieve', + example: + 'require "beagle"\n\nbeagle = Beagle::Client.new(\n api_key: "My API Key",\n environment: "staging" # defaults to "production"\n)\n\ntenant = beagle.tenants.retrieve(123)\n\nputs(tenant)', + }, + csharp: { + method: 'Tenants.Retrieve', + example: + 'TenantRetrieveParams parameters = new() { ID = 123 };\n\nvar tenant = await client.Tenants.Retrieve(parameters);\n\nConsole.WriteLine(tenant);', + }, + http: { + example: + 'curl https://developer.beagleforpm.com/api/tenants/$ID \\\n -H "x-api-key: $BEAGLE_API_KEY"', + }, + }, + }, + { + name: 'update', + endpoint: '/api/tenants/{id}', + httpMethod: 'patch', + summary: 'Update Tenant', + description: 'update an existing tenant by their id.', + stainlessPath: '(resource) tenants > (method) update', + qualified: 'client.tenants.update', + params: [ + 'id: number;', + 'address?: { city: string; state: string; street1: string; zip: string; street2?: string; };', + 'contact?: { email: string; name: { first: string; last: string; }; phone?: string; };', + 'expectedMoveInDate?: string;', + 'expectedMoveOutDate?: string;', + ], + response: + '{ data: { id: number; address: address; contact: contact; expectedMoveInDate?: string; expectedMoveOutDate?: string; }; success: true; }', + markdown: + "## update\n\n`client.tenants.update(id: number, address?: { city: string; state: string; street1: string; zip: string; street2?: string; }, contact?: { email: string; name: object; phone?: string; }, expectedMoveInDate?: string, expectedMoveOutDate?: string): { data: tenant; success: true; }`\n\n**patch** `/api/tenants/{id}`\n\nupdate an existing tenant by their id.\n\n### Parameters\n\n- `id: number`\n\n- `address?: { city: string; state: string; street1: string; zip: string; street2?: string; }`\n - `city: string`\n - `state: string`\n two letter state code, ie CA\n - `street1: string`\n - `zip: string`\n US ZIP or ZIP+4. For example: '94104' or '94104-1234'\n - `street2?: string`\n\n- `contact?: { email: string; name: { first: string; last: string; }; phone?: string; }`\n - `email: string`\n - `name: { first: string; last: string; }`\n - `phone?: string`\n\n- `expectedMoveInDate?: string`\n\n- `expectedMoveOutDate?: string`\n\n### Returns\n\n- `{ data: { id: number; address: address; contact: contact; expectedMoveInDate?: string; expectedMoveOutDate?: string; }; success: true; }`\n\n - `data: { id: number; address: { city: string; state: string; street1: string; zip: string; street2?: string; }; contact: { email: string; name: object; phone?: string; }; expectedMoveInDate?: string; expectedMoveOutDate?: string; }`\n - `success: true`\n\n### Example\n\n```typescript\nimport Beagle from '@corgi-tech/beagle';\n\nconst client = new Beagle();\n\nconst tenant = await client.tenants.update(123);\n\nconsole.log(tenant);\n```", + perLanguage: { + typescript: { + method: 'client.tenants.update', + example: + "import Beagle from '@corgi-tech/beagle';\n\nconst client = new Beagle({\n apiKey: process.env['BEAGLE_API_KEY'], // This is the default and can be omitted\n});\n\nconst tenant = await client.tenants.update(123);\n\nconsole.log(tenant.data);", + }, + python: { + method: 'tenants.update', + example: + 'import os\nfrom beagle import Beagle\n\nclient = Beagle(\n api_key=os.environ.get("BEAGLE_API_KEY"), # This is the default and can be omitted\n)\ntenant = client.tenants.update(\n id=123,\n)\nprint(tenant.data)', + }, + java: { + method: 'tenants().update', + example: + 'package com.beagle.api.example;\n\nimport com.beagle.api.client.BeagleClient;\nimport com.beagle.api.client.okhttp.BeagleOkHttpClient;\nimport com.beagle.api.models.tenants.TenantUpdateParams;\nimport com.beagle.api.models.tenants.TenantUpdateResponse;\n\npublic final class Main {\n private Main() {}\n\n public static void main(String[] args) {\n BeagleClient client = BeagleOkHttpClient.fromEnv();\n\n TenantUpdateResponse tenant = client.tenants().update(123.0);\n }\n}', + }, + go: { + method: 'client.Tenants.Update', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/beagle-go"\n\t"github.com/stainless-sdks/beagle-go/option"\n)\n\nfunc main() {\n\tclient := beagle.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\ttenant, err := client.Tenants.Update(\n\t\tcontext.TODO(),\n\t\t123,\n\t\tbeagle.TenantUpdateParams{},\n\t)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", tenant.Data)\n}\n', + }, + ruby: { + method: 'tenants.update', + example: + 'require "beagle"\n\nbeagle = Beagle::Client.new(\n api_key: "My API Key",\n environment: "staging" # defaults to "production"\n)\n\ntenant = beagle.tenants.update(123)\n\nputs(tenant)', + }, + csharp: { + method: 'Tenants.Update', + example: + 'TenantUpdateParams parameters = new() { ID = 123 };\n\nvar tenant = await client.Tenants.Update(parameters);\n\nConsole.WriteLine(tenant);', + }, + http: { + example: + 'curl https://developer.beagleforpm.com/api/tenants/$ID \\\n -X PATCH \\\n -H \'Content-Type: application/json\' \\\n -H "x-api-key: $BEAGLE_API_KEY" \\\n -d \'{\n "address": {\n "city": "South Salt Lake",\n "state": "UT",\n "street1": "123 Main St.",\n "zip": "84115",\n "street2": "Unit 3"\n },\n "contact": {\n "email": "mark.s@example.com",\n "name": {\n "first": "Mark",\n "last": "Scout"\n },\n "phone": "(123) 456-7890"\n }\n }\'', + }, + }, + }, + { + name: 'delete', + endpoint: '/api/tenants/{id}', + httpMethod: 'delete', + summary: 'Delete Tenant', + description: 'delete an existing tenant by their id.', + stainlessPath: '(resource) tenants > (method) delete', + qualified: 'client.tenants.delete', + params: ['id: number;'], + markdown: + "## delete\n\n`client.tenants.delete(id: number): void`\n\n**delete** `/api/tenants/{id}`\n\ndelete an existing tenant by their id.\n\n### Parameters\n\n- `id: number`\n\n### Example\n\n```typescript\nimport Beagle from '@corgi-tech/beagle';\n\nconst client = new Beagle();\n\nawait client.tenants.delete(123)\n```", + perLanguage: { + typescript: { + method: 'client.tenants.delete', + example: + "import Beagle from '@corgi-tech/beagle';\n\nconst client = new Beagle({\n apiKey: process.env['BEAGLE_API_KEY'], // This is the default and can be omitted\n});\n\nawait client.tenants.delete(123);", + }, + python: { + method: 'tenants.delete', + example: + 'import os\nfrom beagle import Beagle\n\nclient = Beagle(\n api_key=os.environ.get("BEAGLE_API_KEY"), # This is the default and can be omitted\n)\nclient.tenants.delete(\n 123,\n)', + }, + java: { + method: 'tenants().delete', + example: + 'package com.beagle.api.example;\n\nimport com.beagle.api.client.BeagleClient;\nimport com.beagle.api.client.okhttp.BeagleOkHttpClient;\nimport com.beagle.api.models.tenants.TenantDeleteParams;\n\npublic final class Main {\n private Main() {}\n\n public static void main(String[] args) {\n BeagleClient client = BeagleOkHttpClient.fromEnv();\n\n client.tenants().delete(123.0);\n }\n}', + }, + go: { + method: 'client.Tenants.Delete', + example: + 'package main\n\nimport (\n\t"context"\n\n\t"github.com/stainless-sdks/beagle-go"\n\t"github.com/stainless-sdks/beagle-go/option"\n)\n\nfunc main() {\n\tclient := beagle.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\terr := client.Tenants.Delete(context.TODO(), 123)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n}\n', + }, + ruby: { + method: 'tenants.delete', + example: + 'require "beagle"\n\nbeagle = Beagle::Client.new(\n api_key: "My API Key",\n environment: "staging" # defaults to "production"\n)\n\nresult = beagle.tenants.delete(123)\n\nputs(result)', + }, + csharp: { + method: 'Tenants.Delete', + example: + 'TenantDeleteParams parameters = new() { ID = 123 };\n\nawait client.Tenants.Delete(parameters);', + }, + http: { + example: + 'curl https://developer.beagleforpm.com/api/tenants/$ID \\\n -X DELETE \\\n -H "x-api-key: $BEAGLE_API_KEY"', + }, + }, + }, + { + name: 'list', + endpoint: '/api/tenants', + httpMethod: 'get', + summary: 'List Tenants', + description: + 'list all tenants, this endpoint is paginated and allows for queries by individual property manager.', + stainlessPath: '(resource) tenants > (method) list', + qualified: 'client.tenants.list', + params: ['page?: number;', 'propertyManagerId?: number;', 'size?: number;'], + response: '{ data: { items: object[]; pagination: object; }; success: true; }', + markdown: + "## list\n\n`client.tenants.list(page?: number, propertyManagerId?: number, size?: number): { data: object; success: true; }`\n\n**get** `/api/tenants`\n\nlist all tenants, this endpoint is paginated and allows for queries by individual property manager.\n\n### Parameters\n\n- `page?: number`\n Page number to fetch.\n\n- `propertyManagerId?: number`\n\n- `size?: number`\n Number of items per page.\n\n### Returns\n\n- `{ data: { items: object[]; pagination: object; }; success: true; }`\n\n - `data: { items: { id: number; address: object; contact: object; expectedMoveInDate?: string; expectedMoveOutDate?: string; }[]; pagination: { page: number; pages: number; records: number; size: number; }; }`\n - `success: true`\n\n### Example\n\n```typescript\nimport Beagle from '@corgi-tech/beagle';\n\nconst client = new Beagle();\n\nconst tenants = await client.tenants.list();\n\nconsole.log(tenants);\n```", + perLanguage: { + typescript: { + method: 'client.tenants.list', + example: + "import Beagle from '@corgi-tech/beagle';\n\nconst client = new Beagle({\n apiKey: process.env['BEAGLE_API_KEY'], // This is the default and can be omitted\n});\n\nconst tenants = await client.tenants.list();\n\nconsole.log(tenants.data);", + }, + python: { + method: 'tenants.list', + example: + 'import os\nfrom beagle import Beagle\n\nclient = Beagle(\n api_key=os.environ.get("BEAGLE_API_KEY"), # This is the default and can be omitted\n)\ntenants = client.tenants.list()\nprint(tenants.data)', + }, + java: { + method: 'tenants().list', + example: + 'package com.beagle.api.example;\n\nimport com.beagle.api.client.BeagleClient;\nimport com.beagle.api.client.okhttp.BeagleOkHttpClient;\nimport com.beagle.api.models.tenants.TenantListParams;\nimport com.beagle.api.models.tenants.TenantListResponse;\n\npublic final class Main {\n private Main() {}\n\n public static void main(String[] args) {\n BeagleClient client = BeagleOkHttpClient.fromEnv();\n\n TenantListResponse tenants = client.tenants().list();\n }\n}', + }, + go: { + method: 'client.Tenants.List', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/beagle-go"\n\t"github.com/stainless-sdks/beagle-go/option"\n)\n\nfunc main() {\n\tclient := beagle.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\ttenants, err := client.Tenants.List(context.TODO(), beagle.TenantListParams{})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", tenants.Data)\n}\n', + }, + ruby: { + method: 'tenants.list', + example: + 'require "beagle"\n\nbeagle = Beagle::Client.new(\n api_key: "My API Key",\n environment: "staging" # defaults to "production"\n)\n\ntenants = beagle.tenants.list\n\nputs(tenants)', + }, + csharp: { + method: 'Tenants.List', + example: + 'TenantListParams parameters = new();\n\nvar tenants = await client.Tenants.List(parameters);\n\nConsole.WriteLine(tenants);', + }, + http: { + example: 'curl https://developer.beagleforpm.com/api/tenants \\\n -H "x-api-key: $BEAGLE_API_KEY"', + }, + }, + }, + { + name: 'create', + endpoint: '/api/tenants', + httpMethod: 'post', + summary: 'Create Tenant', + description: 'create a new tenant.', + stainlessPath: '(resource) tenants > (method) create', + qualified: 'client.tenants.create', + params: [ + 'address: { city: string; state: string; street1: string; zip: string; street2?: string; };', + 'contact: { email: string; name: { first: string; last: string; }; phone?: string; };', + 'propertyManagerId: number;', + 'expectedMoveInDate?: string;', + 'expectedMoveOutDate?: string;', + ], + response: + '{ data: { id: number; address: address; contact: contact; expectedMoveInDate?: string; expectedMoveOutDate?: string; }; success: true; }', + markdown: + "## create\n\n`client.tenants.create(address: { city: string; state: string; street1: string; zip: string; street2?: string; }, contact: { email: string; name: object; phone?: string; }, propertyManagerId: number, expectedMoveInDate?: string, expectedMoveOutDate?: string): { data: tenant; success: true; }`\n\n**post** `/api/tenants`\n\ncreate a new tenant.\n\n### Parameters\n\n- `address: { city: string; state: string; street1: string; zip: string; street2?: string; }`\n - `city: string`\n - `state: string`\n two letter state code, ie CA\n - `street1: string`\n - `zip: string`\n US ZIP or ZIP+4. For example: '94104' or '94104-1234'\n - `street2?: string`\n\n- `contact: { email: string; name: { first: string; last: string; }; phone?: string; }`\n - `email: string`\n - `name: { first: string; last: string; }`\n - `phone?: string`\n\n- `propertyManagerId: number`\n\n- `expectedMoveInDate?: string`\n\n- `expectedMoveOutDate?: string`\n\n### Returns\n\n- `{ data: { id: number; address: address; contact: contact; expectedMoveInDate?: string; expectedMoveOutDate?: string; }; success: true; }`\n\n - `data: { id: number; address: { city: string; state: string; street1: string; zip: string; street2?: string; }; contact: { email: string; name: object; phone?: string; }; expectedMoveInDate?: string; expectedMoveOutDate?: string; }`\n - `success: true`\n\n### Example\n\n```typescript\nimport Beagle from '@corgi-tech/beagle';\n\nconst client = new Beagle();\n\nconst tenant = await client.tenants.create({\n address: {\n city: 'South Salt Lake',\n state: 'UT',\n street1: '123 Main St.',\n zip: '84115',\n},\n contact: {\n email: 'mark.s@example.com',\n name: { first: 'Mark', last: 'Scout' },\n},\n propertyManagerId: 123,\n});\n\nconsole.log(tenant);\n```", + perLanguage: { + typescript: { + method: 'client.tenants.create', + example: + "import Beagle from '@corgi-tech/beagle';\n\nconst client = new Beagle({\n apiKey: process.env['BEAGLE_API_KEY'], // This is the default and can be omitted\n});\n\nconst tenant = await client.tenants.create({\n address: {\n city: 'South Salt Lake',\n state: 'UT',\n street1: '123 Main St.',\n zip: '84115',\n },\n contact: {\n email: 'mark.s@example.com',\n name: { first: 'Mark', last: 'Scout' },\n },\n propertyManagerId: 123,\n});\n\nconsole.log(tenant.data);", + }, + python: { + method: 'tenants.create', + example: + 'import os\nfrom beagle import Beagle\n\nclient = Beagle(\n api_key=os.environ.get("BEAGLE_API_KEY"), # This is the default and can be omitted\n)\ntenant = client.tenants.create(\n address={\n "city": "South Salt Lake",\n "state": "UT",\n "street1": "123 Main St.",\n "zip": "84115",\n },\n contact={\n "email": "mark.s@example.com",\n "name": {\n "first": "Mark",\n "last": "Scout",\n },\n },\n property_manager_id=123,\n)\nprint(tenant.data)', + }, + java: { + method: 'tenants().create', + example: + 'package com.beagle.api.example;\n\nimport com.beagle.api.client.BeagleClient;\nimport com.beagle.api.client.okhttp.BeagleOkHttpClient;\nimport com.beagle.api.models.tenants.Address;\nimport com.beagle.api.models.tenants.Contact;\nimport com.beagle.api.models.tenants.TenantCreateParams;\nimport com.beagle.api.models.tenants.TenantCreateResponse;\n\npublic final class Main {\n private Main() {}\n\n public static void main(String[] args) {\n BeagleClient client = BeagleOkHttpClient.fromEnv();\n\n TenantCreateParams params = TenantCreateParams.builder()\n .address(Address.builder()\n .city("South Salt Lake")\n .state("UT")\n .street1("123 Main St.")\n .zip("84115")\n .build())\n .contact(Contact.builder()\n .email("mark.s@example.com")\n .name(Contact.Name.builder()\n .first("Mark")\n .last("Scout")\n .build())\n .build())\n .propertyManagerId(123.0)\n .build();\n TenantCreateResponse tenant = client.tenants().create(params);\n }\n}', + }, + go: { + method: 'client.Tenants.New', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/beagle-go"\n\t"github.com/stainless-sdks/beagle-go/option"\n)\n\nfunc main() {\n\tclient := beagle.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\ttenant, err := client.Tenants.New(context.TODO(), beagle.TenantNewParams{\n\t\tAddress: beagle.AddressParam{\n\t\t\tCity: "South Salt Lake",\n\t\t\tState: "UT",\n\t\t\tStreet1: "123 Main St.",\n\t\t\tZip: "84115",\n\t\t},\n\t\tContact: beagle.ContactParam{\n\t\t\tEmail: "mark.s@example.com",\n\t\t\tName: beagle.ContactNameParam{\n\t\t\t\tFirst: "Mark",\n\t\t\t\tLast: "Scout",\n\t\t\t},\n\t\t},\n\t\tPropertyManagerID: 123,\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", tenant.Data)\n}\n', + }, + ruby: { + method: 'tenants.create', + example: + 'require "beagle"\n\nbeagle = Beagle::Client.new(\n api_key: "My API Key",\n environment: "staging" # defaults to "production"\n)\n\ntenant = beagle.tenants.create(\n address: {city: "South Salt Lake", state: "UT", street1: "123 Main St.", zip: "84115"},\n contact: {email: "mark.s@example.com", name: {first: "Mark", last: "Scout"}},\n property_manager_id: 123\n)\n\nputs(tenant)', + }, + csharp: { + method: 'Tenants.Create', + example: + 'TenantCreateParams parameters = new()\n{\n Address = new()\n {\n City = "South Salt Lake",\n State = "UT",\n Street1 = "123 Main St.",\n Zip = "84115",\n Street2 = "Unit 3",\n },\n Contact = new()\n {\n Email = "mark.s@example.com",\n Name = new()\n {\n First = "Mark",\n Last = "Scout",\n },\n Phone = "(123) 456-7890",\n },\n PropertyManagerID = 123,\n};\n\nvar tenant = await client.Tenants.Create(parameters);\n\nConsole.WriteLine(tenant);', + }, + http: { + example: + 'curl https://developer.beagleforpm.com/api/tenants \\\n -H \'Content-Type: application/json\' \\\n -H "x-api-key: $BEAGLE_API_KEY" \\\n -d \'{\n "address": {\n "city": "South Salt Lake",\n "state": "UT",\n "street1": "123 Main St.",\n "zip": "84115",\n "street2": "Unit 3"\n },\n "contact": {\n "email": "mark.s@example.com",\n "name": {\n "first": "Mark",\n "last": "Scout"\n },\n "phone": "(123) 456-7890"\n },\n "propertyManagerId": 123\n }\'', + }, + }, + }, + { + name: 'retrieve', + endpoint: '/api/enrollments/{id}', + httpMethod: 'get', + summary: 'Get Enrollment', + description: 'get a specific enrollment by its id.', + stainlessPath: '(resource) enrollments > (method) retrieve', + qualified: 'client.enrollments.retrieve', + params: ['id: number;'], + response: + '{ data: { id: number; effectiveDate: string; plan: string; propertyManagerId: number; status: string; tenantId: number; note?: string; product?: string; tenant?: tenant; }; success: true; }', + markdown: + "## retrieve\n\n`client.enrollments.retrieve(id: number): { data: enrollment; success: true; }`\n\n**get** `/api/enrollments/{id}`\n\nget a specific enrollment by its id.\n\n### Parameters\n\n- `id: number`\n\n### Returns\n\n- `{ data: { id: number; effectiveDate: string; plan: string; propertyManagerId: number; status: string; tenantId: number; note?: string; product?: string; tenant?: tenant; }; success: true; }`\n\n - `data: { id: number; effectiveDate: string; plan: string; propertyManagerId: number; status: string; tenantId: number; note?: string; product?: string; tenant?: { id: number; address: address; contact: contact; expectedMoveInDate?: string; expectedMoveOutDate?: string; }; }`\n - `success: true`\n\n### Example\n\n```typescript\nimport Beagle from '@corgi-tech/beagle';\n\nconst client = new Beagle();\n\nconst enrollment = await client.enrollments.retrieve(123);\n\nconsole.log(enrollment);\n```", + perLanguage: { + typescript: { + method: 'client.enrollments.retrieve', + example: + "import Beagle from '@corgi-tech/beagle';\n\nconst client = new Beagle({\n apiKey: process.env['BEAGLE_API_KEY'], // This is the default and can be omitted\n});\n\nconst enrollment = await client.enrollments.retrieve(123);\n\nconsole.log(enrollment.data);", + }, + python: { + method: 'enrollments.retrieve', + example: + 'import os\nfrom beagle import Beagle\n\nclient = Beagle(\n api_key=os.environ.get("BEAGLE_API_KEY"), # This is the default and can be omitted\n)\nenrollment = client.enrollments.retrieve(\n 123,\n)\nprint(enrollment.data)', + }, + java: { + method: 'enrollments().retrieve', + example: + 'package com.beagle.api.example;\n\nimport com.beagle.api.client.BeagleClient;\nimport com.beagle.api.client.okhttp.BeagleOkHttpClient;\nimport com.beagle.api.models.enrollments.EnrollmentRetrieveParams;\nimport com.beagle.api.models.enrollments.EnrollmentRetrieveResponse;\n\npublic final class Main {\n private Main() {}\n\n public static void main(String[] args) {\n BeagleClient client = BeagleOkHttpClient.fromEnv();\n\n EnrollmentRetrieveResponse enrollment = client.enrollments().retrieve(123.0);\n }\n}', + }, + go: { + method: 'client.Enrollments.Get', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/beagle-go"\n\t"github.com/stainless-sdks/beagle-go/option"\n)\n\nfunc main() {\n\tclient := beagle.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tenrollment, err := client.Enrollments.Get(context.TODO(), 123)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", enrollment.Data)\n}\n', + }, + ruby: { + method: 'enrollments.retrieve', + example: + 'require "beagle"\n\nbeagle = Beagle::Client.new(\n api_key: "My API Key",\n environment: "staging" # defaults to "production"\n)\n\nenrollment = beagle.enrollments.retrieve(123)\n\nputs(enrollment)', + }, + csharp: { + method: 'Enrollments.Retrieve', + example: + 'EnrollmentRetrieveParams parameters = new() { ID = 123 };\n\nvar enrollment = await client.Enrollments.Retrieve(parameters);\n\nConsole.WriteLine(enrollment);', + }, + http: { + example: + 'curl https://developer.beagleforpm.com/api/enrollments/$ID \\\n -H "x-api-key: $BEAGLE_API_KEY"', + }, + }, + }, + { + name: 'lapse', + endpoint: '/api/enrollments/{id}', + httpMethod: 'delete', + summary: 'Lapse Enrollment', + description: + 'lapses a specific enrollment for a tenant, note that if a tenant has multiple enrollments (e.g., SDR and TLL), each must be lapsed individually', + stainlessPath: '(resource) enrollments > (method) lapse', + qualified: 'client.enrollments.lapse', + params: ['id: number;'], + markdown: + "## lapse\n\n`client.enrollments.lapse(id: number): void`\n\n**delete** `/api/enrollments/{id}`\n\nlapses a specific enrollment for a tenant, note that if a tenant has multiple enrollments (e.g., SDR and TLL), each must be lapsed individually\n\n### Parameters\n\n- `id: number`\n\n### Example\n\n```typescript\nimport Beagle from '@corgi-tech/beagle';\n\nconst client = new Beagle();\n\nawait client.enrollments.lapse(123)\n```", + perLanguage: { + typescript: { + method: 'client.enrollments.lapse', + example: + "import Beagle from '@corgi-tech/beagle';\n\nconst client = new Beagle({\n apiKey: process.env['BEAGLE_API_KEY'], // This is the default and can be omitted\n});\n\nawait client.enrollments.lapse(123);", + }, + python: { + method: 'enrollments.lapse', + example: + 'import os\nfrom beagle import Beagle\n\nclient = Beagle(\n api_key=os.environ.get("BEAGLE_API_KEY"), # This is the default and can be omitted\n)\nclient.enrollments.lapse(\n 123,\n)', + }, + java: { + method: 'enrollments().lapse', + example: + 'package com.beagle.api.example;\n\nimport com.beagle.api.client.BeagleClient;\nimport com.beagle.api.client.okhttp.BeagleOkHttpClient;\nimport com.beagle.api.models.enrollments.EnrollmentLapseParams;\n\npublic final class Main {\n private Main() {}\n\n public static void main(String[] args) {\n BeagleClient client = BeagleOkHttpClient.fromEnv();\n\n client.enrollments().lapse(123.0);\n }\n}', + }, + go: { + method: 'client.Enrollments.Lapse', + example: + 'package main\n\nimport (\n\t"context"\n\n\t"github.com/stainless-sdks/beagle-go"\n\t"github.com/stainless-sdks/beagle-go/option"\n)\n\nfunc main() {\n\tclient := beagle.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\terr := client.Enrollments.Lapse(context.TODO(), 123)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n}\n', + }, + ruby: { + method: 'enrollments.lapse', + example: + 'require "beagle"\n\nbeagle = Beagle::Client.new(\n api_key: "My API Key",\n environment: "staging" # defaults to "production"\n)\n\nresult = beagle.enrollments.lapse(123)\n\nputs(result)', + }, + csharp: { + method: 'Enrollments.Lapse', + example: + 'EnrollmentLapseParams parameters = new() { ID = 123 };\n\nawait client.Enrollments.Lapse(parameters);', + }, + http: { + example: + 'curl https://developer.beagleforpm.com/api/enrollments/$ID \\\n -X DELETE \\\n -H "x-api-key: $BEAGLE_API_KEY"', + }, + }, + }, + { + name: 'list', + endpoint: '/api/enrollments', + httpMethod: 'get', + summary: 'List Enrollments', + description: + 'list all enrollments, this endpoint is paginated and allows for queries by individual property manager.', + stainlessPath: '(resource) enrollments > (method) list', + qualified: 'client.enrollments.list', + params: [ + 'page?: number;', + 'product?: string;', + 'propertyManagerId?: number;', + 'size?: number;', + 'status?: string;', + ], + response: '{ data: { items: object[]; pagination: object; }; success: true; }', + markdown: + "## list\n\n`client.enrollments.list(page?: number, product?: string, propertyManagerId?: number, size?: number, status?: string): { data: object; success: true; }`\n\n**get** `/api/enrollments`\n\nlist all enrollments, this endpoint is paginated and allows for queries by individual property manager.\n\n### Parameters\n\n- `page?: number`\n Page number to fetch.\n\n- `product?: string`\n\n- `propertyManagerId?: number`\n\n- `size?: number`\n Number of items per page.\n\n- `status?: string`\n\n### Returns\n\n- `{ data: { items: object[]; pagination: object; }; success: true; }`\n\n - `data: { items: { id: number; effectiveDate: string; plan: string; propertyManagerId: number; status: string; tenantId: number; note?: string; product?: string; tenant?: object; }[]; pagination: { page: number; pages: number; records: number; size: number; }; }`\n - `success: true`\n\n### Example\n\n```typescript\nimport Beagle from '@corgi-tech/beagle';\n\nconst client = new Beagle();\n\nconst enrollments = await client.enrollments.list();\n\nconsole.log(enrollments);\n```", + perLanguage: { + typescript: { + method: 'client.enrollments.list', + example: + "import Beagle from '@corgi-tech/beagle';\n\nconst client = new Beagle({\n apiKey: process.env['BEAGLE_API_KEY'], // This is the default and can be omitted\n});\n\nconst enrollments = await client.enrollments.list();\n\nconsole.log(enrollments.data);", + }, + python: { + method: 'enrollments.list', + example: + 'import os\nfrom beagle import Beagle\n\nclient = Beagle(\n api_key=os.environ.get("BEAGLE_API_KEY"), # This is the default and can be omitted\n)\nenrollments = client.enrollments.list()\nprint(enrollments.data)', + }, + java: { + method: 'enrollments().list', + example: + 'package com.beagle.api.example;\n\nimport com.beagle.api.client.BeagleClient;\nimport com.beagle.api.client.okhttp.BeagleOkHttpClient;\nimport com.beagle.api.models.enrollments.EnrollmentListParams;\nimport com.beagle.api.models.enrollments.EnrollmentListResponse;\n\npublic final class Main {\n private Main() {}\n\n public static void main(String[] args) {\n BeagleClient client = BeagleOkHttpClient.fromEnv();\n\n EnrollmentListResponse enrollments = client.enrollments().list();\n }\n}', + }, + go: { + method: 'client.Enrollments.List', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/beagle-go"\n\t"github.com/stainless-sdks/beagle-go/option"\n)\n\nfunc main() {\n\tclient := beagle.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tenrollments, err := client.Enrollments.List(context.TODO(), beagle.EnrollmentListParams{})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", enrollments.Data)\n}\n', + }, + ruby: { + method: 'enrollments.list', + example: + 'require "beagle"\n\nbeagle = Beagle::Client.new(\n api_key: "My API Key",\n environment: "staging" # defaults to "production"\n)\n\nenrollments = beagle.enrollments.list\n\nputs(enrollments)', + }, + csharp: { + method: 'Enrollments.List', + example: + 'EnrollmentListParams parameters = new();\n\nvar enrollments = await client.Enrollments.List(parameters);\n\nConsole.WriteLine(enrollments);', + }, + http: { + example: + 'curl https://developer.beagleforpm.com/api/enrollments \\\n -H "x-api-key: $BEAGLE_API_KEY"', + }, + }, + }, + { + name: 'create', + endpoint: '/api/enrollments', + httpMethod: 'post', + summary: 'Create Enrollment', + description: 'create a new enrollment for a tenant.', + stainlessPath: '(resource) enrollments > (method) create', + qualified: 'client.enrollments.create', + params: [ + 'effectiveDate: string;', + 'plan: string;', + 'propertyManagerId: number;', + 'tenantId: number;', + 'note?: string;', + 'product?: string;', + "status?: 'Premium Paying' | 'Issued, Not Paid';", + 'tenant?: { id: number; address: { city: string; state: string; street1: string; zip: string; street2?: string; }; contact: { email: string; name: object; phone?: string; }; expectedMoveInDate?: string; expectedMoveOutDate?: string; };', + ], + response: + '{ data: { id: number; effectiveDate: string; plan: string; propertyManagerId: number; status: string; tenantId: number; note?: string; product?: string; tenant?: tenant; }; success: true; }', + markdown: + "## create\n\n`client.enrollments.create(effectiveDate: string, plan: string, propertyManagerId: number, tenantId: number, note?: string, product?: string, status?: 'Premium Paying' | 'Issued, Not Paid', tenant?: { id: number; address: address; contact: contact; expectedMoveInDate?: string; expectedMoveOutDate?: string; }): { data: enrollment; success: true; }`\n\n**post** `/api/enrollments`\n\ncreate a new enrollment for a tenant.\n\n### Parameters\n\n- `effectiveDate: string`\n the date the enrollment will begin, note enrollments cannot begin in the past\n\n- `plan: string`\n the plan name/code\n\n- `propertyManagerId: number`\n\n- `tenantId: number`\n\n- `note?: string`\n an optional note field, this can be used for easily appending metadata to enrollments\n\n- `product?: string`\n\n- `status?: 'Premium Paying' | 'Issued, Not Paid'`\n the enrollment status — defaults to 'Issued, Not Paid' if not provided\n\n- `tenant?: { id: number; address: { city: string; state: string; street1: string; zip: string; street2?: string; }; contact: { email: string; name: object; phone?: string; }; expectedMoveInDate?: string; expectedMoveOutDate?: string; }`\n - `id: number`\n - `address: { city: string; state: string; street1: string; zip: string; street2?: string; }`\n - `contact: { email: string; name: { first: string; last: string; }; phone?: string; }`\n - `expectedMoveInDate?: string`\n - `expectedMoveOutDate?: string`\n\n### Returns\n\n- `{ data: { id: number; effectiveDate: string; plan: string; propertyManagerId: number; status: string; tenantId: number; note?: string; product?: string; tenant?: tenant; }; success: true; }`\n\n - `data: { id: number; effectiveDate: string; plan: string; propertyManagerId: number; status: string; tenantId: number; note?: string; product?: string; tenant?: { id: number; address: address; contact: contact; expectedMoveInDate?: string; expectedMoveOutDate?: string; }; }`\n - `success: true`\n\n### Example\n\n```typescript\nimport Beagle from '@corgi-tech/beagle';\n\nconst client = new Beagle();\n\nconst enrollment = await client.enrollments.create({\n effectiveDate: '2025-11-10T19:50:20.638Z',\n plan: 'TLL_100K_CONTENTS_5K_ACV',\n propertyManagerId: 123,\n tenantId: 123,\n});\n\nconsole.log(enrollment);\n```", + perLanguage: { + typescript: { + method: 'client.enrollments.create', + example: + "import Beagle from '@corgi-tech/beagle';\n\nconst client = new Beagle({\n apiKey: process.env['BEAGLE_API_KEY'], // This is the default and can be omitted\n});\n\nconst enrollment = await client.enrollments.create({\n effectiveDate: '2025-11-10T19:50:20.638Z',\n plan: 'TLL_100K_CONTENTS_5K_ACV',\n propertyManagerId: 123,\n tenantId: 123,\n});\n\nconsole.log(enrollment.data);", + }, + python: { + method: 'enrollments.create', + example: + 'import os\nfrom beagle import Beagle\n\nclient = Beagle(\n api_key=os.environ.get("BEAGLE_API_KEY"), # This is the default and can be omitted\n)\nenrollment = client.enrollments.create(\n effective_date="2025-11-10T19:50:20.638Z",\n plan="TLL_100K_CONTENTS_5K_ACV",\n property_manager_id=123,\n tenant_id=123,\n)\nprint(enrollment.data)', + }, + java: { + method: 'enrollments().create', + example: + 'package com.beagle.api.example;\n\nimport com.beagle.api.client.BeagleClient;\nimport com.beagle.api.client.okhttp.BeagleOkHttpClient;\nimport com.beagle.api.models.enrollments.EnrollmentCreateParams;\nimport com.beagle.api.models.enrollments.EnrollmentCreateResponse;\n\npublic final class Main {\n private Main() {}\n\n public static void main(String[] args) {\n BeagleClient client = BeagleOkHttpClient.fromEnv();\n\n EnrollmentCreateParams params = EnrollmentCreateParams.builder()\n .effectiveDate("2025-11-10T19:50:20.638Z")\n .plan("TLL_100K_CONTENTS_5K_ACV")\n .propertyManagerId(123.0)\n .tenantId(123.0)\n .build();\n EnrollmentCreateResponse enrollment = client.enrollments().create(params);\n }\n}', + }, + go: { + method: 'client.Enrollments.New', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/beagle-go"\n\t"github.com/stainless-sdks/beagle-go/option"\n)\n\nfunc main() {\n\tclient := beagle.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tenrollment, err := client.Enrollments.New(context.TODO(), beagle.EnrollmentNewParams{\n\t\tEffectiveDate: "2025-11-10T19:50:20.638Z",\n\t\tPlan: "TLL_100K_CONTENTS_5K_ACV",\n\t\tPropertyManagerID: 123,\n\t\tTenantID: 123,\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", enrollment.Data)\n}\n', + }, + ruby: { + method: 'enrollments.create', + example: + 'require "beagle"\n\nbeagle = Beagle::Client.new(\n api_key: "My API Key",\n environment: "staging" # defaults to "production"\n)\n\nenrollment = beagle.enrollments.create(\n effective_date: "2025-11-10T19:50:20.638Z",\n plan: "TLL_100K_CONTENTS_5K_ACV",\n property_manager_id: 123,\n tenant_id: 123\n)\n\nputs(enrollment)', + }, + csharp: { + method: 'Enrollments.Create', + example: + 'EnrollmentCreateParams parameters = new()\n{\n EffectiveDate = "2025-11-10T19:50:20.638Z",\n Plan = "TLL_100K_CONTENTS_5K_ACV",\n PropertyManagerID = 123,\n TenantID = 123,\n};\n\nvar enrollment = await client.Enrollments.Create(parameters);\n\nConsole.WriteLine(enrollment);', + }, + http: { + example: + 'curl https://developer.beagleforpm.com/api/enrollments \\\n -H \'Content-Type: application/json\' \\\n -H "x-api-key: $BEAGLE_API_KEY" \\\n -d \'{\n "effectiveDate": "2025-11-10T19:50:20.638Z",\n "plan": "TLL_100K_CONTENTS_5K_ACV",\n "propertyManagerId": 123,\n "tenantId": 123,\n "status": "Issued, Not Paid",\n "tenant": {\n "id": 123,\n "address": {\n "city": "South Salt Lake",\n "state": "UT",\n "street1": "123 Main St.",\n "zip": "84115",\n "street2": "Unit 3"\n },\n "contact": {\n "email": "mark.s@example.com",\n "name": {\n "first": "Mark",\n "last": "Scout"\n },\n "phone": "(123) 456-7890"\n }\n }\n }\'', + }, + }, + }, + { + name: 'retrieve_certificate', + endpoint: '/api/enrollments/{id}/certificate', + httpMethod: 'get', + summary: 'Get Enrollment Certificate', + description: 'get the certificate of enrollment for a given enrollment', + stainlessPath: '(resource) enrollments > (method) retrieve_certificate', + qualified: 'client.enrollments.retrieveCertificate', + params: ['id: number;'], + response: 'string', + markdown: + "## retrieve_certificate\n\n`client.enrollments.retrieveCertificate(id: number): string`\n\n**get** `/api/enrollments/{id}/certificate`\n\nget the certificate of enrollment for a given enrollment\n\n### Parameters\n\n- `id: number`\n\n### Returns\n\n- `string`\n\n### Example\n\n```typescript\nimport Beagle from '@corgi-tech/beagle';\n\nconst client = new Beagle();\n\nconst response = await client.enrollments.retrieveCertificate(123);\n\nconsole.log(response);\n\nconst content = await response.blob()\nconsole.log(content)\n```", + perLanguage: { + typescript: { + method: 'client.enrollments.retrieveCertificate', + example: + "import Beagle from '@corgi-tech/beagle';\n\nconst client = new Beagle({\n apiKey: process.env['BEAGLE_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.enrollments.retrieveCertificate(123);\n\nconsole.log(response);\n\nconst content = await response.blob();\nconsole.log(content);", + }, + python: { + method: 'enrollments.retrieve_certificate', + example: + 'import os\nfrom beagle import Beagle\n\nclient = Beagle(\n api_key=os.environ.get("BEAGLE_API_KEY"), # This is the default and can be omitted\n)\nresponse = client.enrollments.retrieve_certificate(\n 123,\n)\nprint(response)\ncontent = response.read()\nprint(content)', + }, + java: { + method: 'enrollments().retrieveCertificate', + example: + 'package com.beagle.api.example;\n\nimport com.beagle.api.client.BeagleClient;\nimport com.beagle.api.client.okhttp.BeagleOkHttpClient;\nimport com.beagle.api.core.http.HttpResponse;\nimport com.beagle.api.models.enrollments.EnrollmentRetrieveCertificateParams;\n\npublic final class Main {\n private Main() {}\n\n public static void main(String[] args) {\n BeagleClient client = BeagleOkHttpClient.fromEnv();\n\n HttpResponse response = client.enrollments().retrieveCertificate(123.0);\n }\n}', + }, + go: { + method: 'client.Enrollments.GetCertificate', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/beagle-go"\n\t"github.com/stainless-sdks/beagle-go/option"\n)\n\nfunc main() {\n\tclient := beagle.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tresponse, err := client.Enrollments.GetCertificate(context.TODO(), 123)\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", response)\n}\n', + }, + ruby: { + method: 'enrollments.retrieve_certificate', + example: + 'require "beagle"\n\nbeagle = Beagle::Client.new(\n api_key: "My API Key",\n environment: "staging" # defaults to "production"\n)\n\nresponse = beagle.enrollments.retrieve_certificate(123)\n\nputs(response)', + }, + csharp: { + method: 'Enrollments.RetrieveCertificate', + example: + 'EnrollmentRetrieveCertificateParams parameters = new() { ID = 123 };\n\nvar response = await client.Enrollments.RetrieveCertificate(parameters);\n\nConsole.WriteLine(response);', + }, + http: { + example: + 'curl https://developer.beagleforpm.com/api/enrollments/$ID/certificate \\\n -H "x-api-key: $BEAGLE_API_KEY"', + }, + }, + }, + { + name: 'verify', + endpoint: '/api/insurance-verification', + httpMethod: 'post', + summary: 'Verify a tenants insurance policy', + description: 'trigger a job to parse a tenants insurance document(s)', + stainlessPath: '(resource) insurance_verification > (method) verify', + qualified: 'client.insuranceVerification.verify', + params: ['propertyManagerId: number;', 'tenantId: number;', 'urls: string[];'], + response: "{ message: 'insurance verification job scheduled'; }", + markdown: + "## verify\n\n`client.insuranceVerification.verify(propertyManagerId: number, tenantId: number, urls: string[]): { message: 'insurance verification job scheduled'; }`\n\n**post** `/api/insurance-verification`\n\ntrigger a job to parse a tenants insurance document(s)\n\n### Parameters\n\n- `propertyManagerId: number`\n\n- `tenantId: number`\n\n- `urls: string[]`\n an array of presigned pdf urls for the tenants policy document(s)\n\n### Returns\n\n- `{ message: 'insurance verification job scheduled'; }`\n\n - `message: 'insurance verification job scheduled'`\n\n### Example\n\n```typescript\nimport Beagle from '@corgi-tech/beagle';\n\nconst client = new Beagle();\n\nconst response = await client.insuranceVerification.verify({\n propertyManagerId: 0,\n tenantId: 0,\n urls: ['string'],\n});\n\nconsole.log(response);\n```", + perLanguage: { + typescript: { + method: 'client.insuranceVerification.verify', + example: + "import Beagle from '@corgi-tech/beagle';\n\nconst client = new Beagle({\n apiKey: process.env['BEAGLE_API_KEY'], // This is the default and can be omitted\n});\n\nconst response = await client.insuranceVerification.verify({\n propertyManagerId: 0,\n tenantId: 0,\n urls: ['string'],\n});\n\nconsole.log(response.message);", + }, + python: { + method: 'insurance_verification.verify', + example: + 'import os\nfrom beagle import Beagle\n\nclient = Beagle(\n api_key=os.environ.get("BEAGLE_API_KEY"), # This is the default and can be omitted\n)\nresponse = client.insurance_verification.verify(\n property_manager_id=0,\n tenant_id=0,\n urls=["string"],\n)\nprint(response.message)', + }, + java: { + method: 'insuranceVerification().verify', + example: + 'package com.beagle.api.example;\n\nimport com.beagle.api.client.BeagleClient;\nimport com.beagle.api.client.okhttp.BeagleOkHttpClient;\nimport com.beagle.api.models.insuranceverification.InsuranceVerificationVerifyParams;\nimport com.beagle.api.models.insuranceverification.InsuranceVerificationVerifyResponse;\n\npublic final class Main {\n private Main() {}\n\n public static void main(String[] args) {\n BeagleClient client = BeagleOkHttpClient.fromEnv();\n\n InsuranceVerificationVerifyParams params = InsuranceVerificationVerifyParams.builder()\n .propertyManagerId(0.0)\n .tenantId(0.0)\n .addUrl("string")\n .build();\n InsuranceVerificationVerifyResponse response = client.insuranceVerification().verify(params);\n }\n}', + }, + go: { + method: 'client.InsuranceVerification.Verify', + example: + 'package main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/beagle-go"\n\t"github.com/stainless-sdks/beagle-go/option"\n)\n\nfunc main() {\n\tclient := beagle.NewClient(\n\t\toption.WithAPIKey("My API Key"),\n\t)\n\tresponse, err := client.InsuranceVerification.Verify(context.TODO(), beagle.InsuranceVerificationVerifyParams{\n\t\tPropertyManagerID: 0,\n\t\tTenantID: 0,\n\t\tURLs: []string{"string"},\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", response.Message)\n}\n', + }, + ruby: { + method: 'insurance_verification.verify', + example: + 'require "beagle"\n\nbeagle = Beagle::Client.new(\n api_key: "My API Key",\n environment: "staging" # defaults to "production"\n)\n\nresponse = beagle.insurance_verification.verify(property_manager_id: 0, tenant_id: 0, urls: ["string"])\n\nputs(response)', + }, + csharp: { + method: 'InsuranceVerification.Verify', + example: + 'InsuranceVerificationVerifyParams parameters = new()\n{\n PropertyManagerID = 0,\n TenantID = 0,\n Urls =\n [\n "string"\n ],\n};\n\nvar response = await client.InsuranceVerification.Verify(parameters);\n\nConsole.WriteLine(response);', + }, + http: { + example: + 'curl https://developer.beagleforpm.com/api/insurance-verification \\\n -H \'Content-Type: application/json\' \\\n -H "x-api-key: $BEAGLE_API_KEY" \\\n -d \'{\n "propertyManagerId": 0,\n "tenantId": 0,\n "urls": [\n "string"\n ]\n }\'', + }, + }, + }, +]; + +const EMBEDDED_READMES: { language: string; content: string }[] = [ + { + language: 'csharp', + content: + '# Beagle C# API Library\n\nThe Beagle C# SDK provides convenient access to the Beagle REST API from applications written in C#.\n\n## Installation\n\n```bash\ngit clone git@github.com:stainless-sdks/beagle-csharp.git\ndotnet add reference beagle-csharp/src/Beagle\n```\n\n## Requirements\n\nThis library requires .NET Standard 2.0 or later.\n\n## Usage\n\nSee the [`examples`](examples) directory for complete and runnable examples.\n\n```csharp\nBeagleClient client = new();\n\nPlanListParams parameters = new();\n\nvar plans = await client.Plans.List(parameters);\n\nConsole.WriteLine(plans);\n```', + }, + { + language: 'go', + content: + '# Beagle Go API Library\n\nGo Reference\n\nThe Beagle Go library provides convenient access to the Beagle REST API\nfrom applications written in Go.\n\nIt is generated with [Stainless](https://www.stainless.com/).\n\n## MCP Server\n\nUse the Beagle MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application.\n\n[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=%40corgi-tech%2Fbeagle-mcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkBjb3JnaS10ZWNoL2JlYWdsZS1tY3AiXSwiZW52Ijp7IkJFQUdMRV9BUElfS0VZIjoiTXkgQVBJIEtleSJ9fQ)\n[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22%40corgi-tech%2Fbeagle-mcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40corgi-tech%2Fbeagle-mcp%22%5D%2C%22env%22%3A%7B%22BEAGLE_API_KEY%22%3A%22My%20API%20Key%22%7D%7D)\n\n> Note: You may need to set environment variables in your MCP client.\n\n## Installation\n\n\n\n```go\nimport (\n\t"github.com/stainless-sdks/beagle-go" // imported as SDK_PackageName\n)\n```\n\n\n\nOr to pin the version:\n\n\n\n```sh\ngo get -u \'github.com/stainless-sdks/beagle-go@v0.0.1\'\n```\n\n\n\n## Requirements\n\nThis library requires Go 1.22+.\n\n## Usage\n\nThe full API of this library can be found in [api.md](api.md).\n\n```go\npackage main\n\nimport (\n\t"context"\n\t"fmt"\n\n\t"github.com/stainless-sdks/beagle-go"\n\t"github.com/stainless-sdks/beagle-go/option"\n)\n\nfunc main() {\n\tclient := beagle.NewClient(\n\t\toption.WithAPIKey("My API Key"), // defaults to os.LookupEnv("BEAGLE_API_KEY")\n\t\toption.WithEnvironmentStaging(), // defaults to option.WithEnvironmentProduction()\n\t)\n\tplans, err := client.Plans.List(context.TODO())\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf("%+v\\n", plans.Data)\n}\n\n```\n\n### Request fields\n\nAll request parameters are wrapped in a generic `Field` type,\nwhich we use to distinguish zero values from null or omitted fields.\n\nThis prevents accidentally sending a zero value if you forget a required parameter,\nand enables explicitly sending `null`, `false`, `\'\'`, or `0` on optional parameters.\nAny field not specified is not sent.\n\nTo construct fields with values, use the helpers `String()`, `Int()`, `Float()`, or most commonly, the generic `F[T]()`.\nTo send a null, use `Null[T]()`, and to send a nonconforming value, use `Raw[T](any)`. For example:\n\n```go\nparams := FooParams{\n\tName: SDK_PackageName.F("hello"),\n\n\t// Explicitly send `"description": null`\n\tDescription: SDK_PackageName.Null[string](),\n\n\tPoint: SDK_PackageName.F(SDK_PackageName.Point{\n\t\tX: SDK_PackageName.Int(0),\n\t\tY: SDK_PackageName.Int(1),\n\n\t\t// In cases where the API specifies a given type,\n\t\t// but you want to send something else, use `Raw`:\n\t\tZ: SDK_PackageName.Raw[int64](0.01), // sends a float\n\t}),\n}\n```\n\n### Response objects\n\nAll fields in response structs are value types (not pointers or wrappers).\n\nIf a given field is `null`, not present, or invalid, the corresponding field\nwill simply be its zero value.\n\nAll response structs also include a special `JSON` field, containing more detailed\ninformation about each property, which you can use like so:\n\n```go\nif res.Name == "" {\n\t// true if `"name"` is either not present or explicitly null\n\tres.JSON.Name.IsNull()\n\n\t// true if the `"name"` key was not present in the response JSON at all\n\tres.JSON.Name.IsMissing()\n\n\t// When the API returns data that cannot be coerced to the expected type:\n\tif res.JSON.Name.IsInvalid() {\n\t\traw := res.JSON.Name.Raw()\n\n\t\tlegacyName := struct{\n\t\t\tFirst string `json:"first"`\n\t\t\tLast string `json:"last"`\n\t\t}{}\n\t\tjson.Unmarshal([]byte(raw), &legacyName)\n\t\tname = legacyName.First + " " + legacyName.Last\n\t}\n}\n```\n\nThese `.JSON` structs also include an `Extras` map containing\nany properties in the json response that were not specified\nin the struct. This can be useful for API features not yet\npresent in the SDK.\n\n```go\nbody := res.JSON.ExtraFields["my_unexpected_field"].Raw()\n```\n\n### RequestOptions\n\nThis library uses the functional options pattern. Functions defined in the\n`SDK_PackageOptionName` package return a `RequestOption`, which is a closure that mutates a\n`RequestConfig`. These options can be supplied to the client or at individual\nrequests. For example:\n\n```go\nclient := SDK_PackageName.SDK_ClientInitializerName(\n\t// Adds a header to every request made by the client\n\tSDK_PackageOptionName.WithHeader("X-Some-Header", "custom_header_info"),\n)\n\nclient.Plans.List(context.TODO(), ...,\n\t// Override the header\n\tSDK_PackageOptionName.WithHeader("X-Some-Header", "some_other_custom_header_info"),\n\t// Add an undocumented field to the request body, using sjson syntax\n\tSDK_PackageOptionName.WithJSONSet("some.json.path", map[string]string{"my": "object"}),\n)\n```\n\nSee the [full list of request options](https://pkg.go.dev/github.com/stainless-sdks/beagle-go/SDK_PackageOptionName).\n\n### Pagination\n\nThis library provides some conveniences for working with paginated list endpoints.\n\nYou can use `.ListAutoPaging()` methods to iterate through items across all pages:\n\n\n\nOr you can use simple `.List()` methods to fetch a single page and receive a standard response object\nwith additional helper methods like `.GetNextPage()`, e.g.:\n\n\n\n### Errors\n\nWhen the API returns a non-success status code, we return an error with type\n`*SDK_PackageName.Error`. This contains the `StatusCode`, `*http.Request`, and\n`*http.Response` values of the request, as well as the JSON of the error body\n(much like other response objects in the SDK).\n\nTo handle errors, we recommend that you use the `errors.As` pattern:\n\n```go\n_, err := client.Plans.List(context.TODO())\nif err != nil {\n\tvar apierr *beagle.Error\n\tif errors.As(err, &apierr) {\n\t\tprintln(string(apierr.DumpRequest(true))) // Prints the serialized HTTP request\n\t\tprintln(string(apierr.DumpResponse(true))) // Prints the serialized HTTP response\n\t}\n\tpanic(err.Error()) // GET "/api/plans": 400 Bad Request { ... }\n}\n```\n\nWhen other errors occur, they are returned unwrapped; for example,\nif HTTP transport fails, you might receive `*url.Error` wrapping `*net.OpError`.\n\n### Timeouts\n\nRequests do not time out by default; use context to configure a timeout for a request lifecycle.\n\nNote that if a request is [retried](#retries), the context timeout does not start over.\nTo set a per-retry timeout, use `SDK_PackageOptionName.WithRequestTimeout()`.\n\n```go\n// This sets the timeout for the request, including all the retries.\nctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute)\ndefer cancel()\nclient.Plans.List(\n\tctx,\n\t// This sets the per-retry timeout\n\toption.WithRequestTimeout(20*time.Second),\n)\n```\n\n### File uploads\n\nRequest parameters that correspond to file uploads in multipart requests are typed as\n`param.Field[io.Reader]`. The contents of the `io.Reader` will by default be sent as a multipart form\npart with the file name of "anonymous_file" and content-type of "application/octet-stream".\n\nThe file name and content-type can be customized by implementing `Name() string` or `ContentType()\nstring` on the run-time type of `io.Reader`. Note that `os.File` implements `Name() string`, so a\nfile returned by `os.Open` will be sent with the file name on disk.\n\nWe also provide a helper `SDK_PackageName.FileParam(reader io.Reader, filename string, contentType string)`\nwhich can be used to wrap any `io.Reader` with the appropriate file name and content type.\n\n\n\n### Retries\n\nCertain errors will be automatically retried 2 times by default, with a short exponential backoff.\nWe retry by default all connection errors, 408 Request Timeout, 409 Conflict, 429 Rate Limit,\nand >=500 Internal errors.\n\nYou can use the `WithMaxRetries` option to configure or disable this:\n\n```go\n// Configure the default for all requests:\nclient := beagle.NewClient(\n\toption.WithMaxRetries(0), // default is 2\n)\n\n// Override per-request:\nclient.Plans.List(context.TODO(), option.WithMaxRetries(5))\n```\n\n\n### Accessing raw response data (e.g. response headers)\n\nYou can access the raw HTTP response data by using the `option.WithResponseInto()` request option. This is useful when\nyou need to examine response headers, status codes, or other details.\n\n```go\n// Create a variable to store the HTTP response\nvar response *http.Response\nplans, err := client.Plans.List(context.TODO(), option.WithResponseInto(&response))\nif err != nil {\n\t// handle error\n}\nfmt.Printf("%+v\\n", plans)\n\nfmt.Printf("Status Code: %d\\n", response.StatusCode)\nfmt.Printf("Headers: %+#v\\n", response.Header)\n```\n\n### Making custom/undocumented requests\n\nThis library is typed for convenient access to the documented API. If you need to access undocumented\nendpoints, params, or response properties, the library can still be used.\n\n#### Undocumented endpoints\n\nTo make requests to undocumented endpoints, you can use `client.Get`, `client.Post`, and other HTTP verbs.\n`RequestOptions` on the client, such as retries, will be respected when making these requests.\n\n```go\nvar (\n // params can be an io.Reader, a []byte, an encoding/json serializable object,\n // or a "…Params" struct defined in this library.\n params map[string]interface{}\n\n // result can be an []byte, *http.Response, a encoding/json deserializable object,\n // or a model defined in this library.\n result *http.Response\n)\nerr := client.Post(context.Background(), "/unspecified", params, &result)\nif err != nil {\n …\n}\n```\n\n#### Undocumented request params\n\nTo make requests using undocumented parameters, you may use either the `SDK_PackageOptionName.WithQuerySet()`\nor the `SDK_PackageOptionName.WithJSONSet()` methods.\n\n```go\nparams := FooNewParams{\n ID: SDK_PackageName.F("id_xxxx"),\n Data: SDK_PackageName.F(FooNewParamsData{\n FirstName: SDK_PackageName.F("John"),\n }),\n}\nclient.Foo.New(context.Background(), params, SDK_PackageOptionName.WithJSONSet("data.last_name", "Doe"))\n```\n\n#### Undocumented response properties\n\nTo access undocumented response properties, you may either access the raw JSON of the response as a string\nwith `result.JSON.RawJSON()`, or get the raw JSON of a particular field on the result with\n`result.JSON.Foo.Raw()`.\n\nAny fields that are not present on the response struct will be saved and can be accessed by `result.JSON.ExtraFields()` which returns the extra fields as a `map[string]Field`.\n\n### Middleware\n\nWe provide `SDK_PackageOptionName.WithMiddleware` which applies the given\nmiddleware to requests.\n\n```go\nfunc Logger(req *http.Request, next SDK_PackageOptionName.MiddlewareNext) (res *http.Response, err error) {\n\t// Before the request\n\tstart := time.Now()\n\tLogReq(req)\n\n\t// Forward the request to the next handler\n\tres, err = next(req)\n\n\t// Handle stuff after the request\n\tend := time.Now()\n\tLogRes(res, err, start - end)\n\n return res, err\n}\n\nclient := SDK_PackageName.SDK_ClientInitializerName(\n\tSDK_PackageOptionName.WithMiddleware(Logger),\n)\n```\n\nWhen multiple middlewares are provided as variadic arguments, the middlewares\nare applied left to right. If `SDK_PackageOptionName.WithMiddleware` is given\nmultiple times, for example first in the client then the method, the\nmiddleware in the client will run first and the middleware given in the method\nwill run next.\n\nYou may also replace the default `http.Client` with\n`SDK_PackageOptionName.WithHTTPClient(client)`. Only one http client is\naccepted (this overwrites any previous client) and receives requests after any\nmiddleware has been applied.\n\n## Semantic versioning\n\nThis package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions:\n\n1. 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.)_\n2. Changes that we do not expect to impact the vast majority of users in practice.\n\nWe take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience.\n\nWe are keen for your feedback; please open an [issue](https://www.github.com/stainless-sdks/beagle-go/issues) with questions, bugs, or suggestions.\n\n## Contributing\n\nSee [the contributing documentation](./CONTRIBUTING.md).\n', + }, + { + language: 'java', + content: + '# Beagle Java API Library\n\n\n[![Maven Central](https://img.shields.io/maven-central/v/com.beagle.api/beagle-java)](https://central.sonatype.com/artifact/com.beagle.api/beagle-java/0.0.1)\n[![javadoc](https://javadoc.io/badge2/com.beagle.api/beagle-java/0.0.1/javadoc.svg)](https://javadoc.io/doc/com.beagle.api/beagle-java/0.0.1)\n\n\nThe Beagle Java SDK provides convenient access to the Beagle REST API from applications written in Java.\n\n\n\nIt is generated with [Stainless](https://www.stainless.com/).\n\n## MCP Server\n\nUse the Beagle MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application.\n\n[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=%40corgi-tech%2Fbeagle-mcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkBjb3JnaS10ZWNoL2JlYWdsZS1tY3AiXSwiZW52Ijp7IkJFQUdMRV9BUElfS0VZIjoiTXkgQVBJIEtleSJ9fQ)\n[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22%40corgi-tech%2Fbeagle-mcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40corgi-tech%2Fbeagle-mcp%22%5D%2C%22env%22%3A%7B%22BEAGLE_API_KEY%22%3A%22My%20API%20Key%22%7D%7D)\n\n> Note: You may need to set environment variables in your MCP client.\n\nJavadocs are available on [javadoc.io](https://javadoc.io/doc/com.beagle.api/beagle-java/0.0.1).\n\n## Installation\n\n### Gradle\n\n~~~kotlin\nimplementation("com.beagle.api:beagle-java:0.0.1")\n~~~\n\n### Maven\n\n~~~xml\n\n com.beagle.api\n beagle-java\n 0.0.1\n\n~~~\n\n## Requirements\n\nThis library requires Java 8 or later.\n\n## Usage\n\n```java\nimport com.beagle.api.client.BeagleClient;\nimport com.beagle.api.client.okhttp.BeagleOkHttpClient;\nimport com.beagle.api.models.plans.PlanListParams;\nimport com.beagle.api.models.plans.PlanListResponse;\n\n// Configures using the `beagle.apiKey` and `beagle.baseUrl` system properties\n// Or configures using the `BEAGLE_API_KEY` and `BEAGLE_BASE_URL` environment variables\nBeagleClient client = BeagleOkHttpClient.fromEnv();\n\nPlanListResponse plans = client.plans().list();\n```\n\n## Client configuration\n\nConfigure the client using system properties or environment variables:\n\n```java\nimport com.beagle.api.client.BeagleClient;\nimport com.beagle.api.client.okhttp.BeagleOkHttpClient;\n\n// Configures using the `beagle.apiKey` and `beagle.baseUrl` system properties\n// Or configures using the `BEAGLE_API_KEY` and `BEAGLE_BASE_URL` environment variables\nBeagleClient client = BeagleOkHttpClient.fromEnv();\n```\n\nOr manually:\n\n```java\nimport com.beagle.api.client.BeagleClient;\nimport com.beagle.api.client.okhttp.BeagleOkHttpClient;\n\nBeagleClient client = BeagleOkHttpClient.builder()\n .apiKey("My API Key")\n .build();\n```\n\nOr using a combination of the two approaches:\n\n```java\nimport com.beagle.api.client.BeagleClient;\nimport com.beagle.api.client.okhttp.BeagleOkHttpClient;\n\nBeagleClient client = BeagleOkHttpClient.builder()\n // Configures using the `beagle.apiKey` and `beagle.baseUrl` system properties\n // Or configures using the `BEAGLE_API_KEY` and `BEAGLE_BASE_URL` environment variables\n .fromEnv()\n .apiKey("My API Key")\n .build();\n```\n\nSee this table for the available options:\n\n| Setter | System property | Environment variable | Required | Default value |\n| --------- | ---------------- | -------------------- | -------- | ------------------------------------- |\n| `apiKey` | `beagle.apiKey` | `BEAGLE_API_KEY` | true | - |\n| `baseUrl` | `beagle.baseUrl` | `BEAGLE_BASE_URL` | true | `"https://developer.beagleforpm.com"` |\n\nSystem properties take precedence over environment variables.\n\n> [!TIP]\n> Don\'t create more than one client in the same application. Each client has a connection pool and\n> thread pools, which are more efficient to share between requests.\n\n### Modifying configuration\n\nTo temporarily use a modified client configuration, while reusing the same connection and thread pools, call `withOptions()` on any client or service:\n\n```java\nimport com.beagle.api.client.BeagleClient;\n\nBeagleClient clientWithOptions = client.withOptions(optionsBuilder -> {\n optionsBuilder.baseUrl("https://example.com");\n optionsBuilder.maxRetries(42);\n});\n```\n\nThe `withOptions()` method does not affect the original client or service.\n\n## Requests and responses\n\nTo send a request to the Beagle API, build an instance of some `Params` class and pass it to the corresponding client method. When the response is received, it will be deserialized into an instance of a Java class.\n\nFor example, `client.plans().list(...)` should be called with an instance of `PlanListParams`, and it will return an instance of `PlanListResponse`.\n\n## Immutability\n\nEach class in the SDK has an associated [builder](https://blogs.oracle.com/javamagazine/post/exploring-joshua-blochs-builder-design-pattern-in-java) or factory method for constructing it.\n\nEach class is [immutable](https://docs.oracle.com/javase/tutorial/essential/concurrency/immutable.html) once constructed. If the class has an associated builder, then it has a `toBuilder()` method, which can be used to convert it back to a builder for making a modified copy.\n\nBecause each class is immutable, builder modification will _never_ affect already built class instances.\n\n## Asynchronous execution\n\nThe default client is synchronous. To switch to asynchronous execution, call the `async()` method:\n\n```java\nimport com.beagle.api.client.BeagleClient;\nimport com.beagle.api.client.okhttp.BeagleOkHttpClient;\nimport com.beagle.api.models.plans.PlanListParams;\nimport com.beagle.api.models.plans.PlanListResponse;\nimport java.util.concurrent.CompletableFuture;\n\n// Configures using the `beagle.apiKey` and `beagle.baseUrl` system properties\n// Or configures using the `BEAGLE_API_KEY` and `BEAGLE_BASE_URL` environment variables\nBeagleClient client = BeagleOkHttpClient.fromEnv();\n\nCompletableFuture plans = client.async().plans().list();\n```\n\nOr create an asynchronous client from the beginning:\n\n```java\nimport com.beagle.api.client.BeagleClientAsync;\nimport com.beagle.api.client.okhttp.BeagleOkHttpClientAsync;\nimport com.beagle.api.models.plans.PlanListParams;\nimport com.beagle.api.models.plans.PlanListResponse;\nimport java.util.concurrent.CompletableFuture;\n\n// Configures using the `beagle.apiKey` and `beagle.baseUrl` system properties\n// Or configures using the `BEAGLE_API_KEY` and `BEAGLE_BASE_URL` environment variables\nBeagleClientAsync client = BeagleOkHttpClientAsync.fromEnv();\n\nCompletableFuture plans = client.plans().list();\n```\n\nThe asynchronous client supports the same options as the synchronous one, except most methods return `CompletableFuture`s.\n\n\n\n\n\n## Binary responses\n\nThe SDK defines methods that return binary responses, which are used for API responses that shouldn\'t necessarily be parsed, like non-JSON data.\n\nThese methods return [`HttpResponse`](beagle-java-core/src/main/kotlin/com/beagle/api/core/http/HttpResponse.kt):\n\n```java\nimport com.beagle.api.core.http.HttpResponse;\nimport com.beagle.api.models.enrollments.EnrollmentRetrieveCertificateParams;\n\nHttpResponse response = client.enrollments().retrieveCertificate(123.0);\n```\n\nTo save the response content to a file, use the [`Files.copy(...)`](https://docs.oracle.com/javase/8/docs/api/java/nio/file/Files.html#copy-java.io.InputStream-java.nio.file.Path-java.nio.file.CopyOption...-) method:\n\n```java\nimport com.beagle.api.core.http.HttpResponse;\nimport java.nio.file.Files;\nimport java.nio.file.Paths;\nimport java.nio.file.StandardCopyOption;\n\ntry (HttpResponse response = client.enrollments().retrieveCertificate(params)) {\n Files.copy(\n response.body(),\n Paths.get(path),\n StandardCopyOption.REPLACE_EXISTING\n );\n} catch (Exception e) {\n System.out.println("Something went wrong!");\n throw new RuntimeException(e);\n}\n```\n\nOr transfer the response content to any [`OutputStream`](https://docs.oracle.com/javase/8/docs/api/java/io/OutputStream.html):\n\n```java\nimport com.beagle.api.core.http.HttpResponse;\nimport java.nio.file.Files;\nimport java.nio.file.Paths;\n\ntry (HttpResponse response = client.enrollments().retrieveCertificate(params)) {\n response.body().transferTo(Files.newOutputStream(Paths.get(path)));\n} catch (Exception e) {\n System.out.println("Something went wrong!");\n throw new RuntimeException(e);\n}\n```\n\n## Raw responses\n\nThe SDK defines methods that deserialize responses into instances of Java classes. However, these methods don\'t provide access to the response headers, status code, or the raw response body.\n\nTo access this data, prefix any HTTP method call on a client or service with `withRawResponse()`:\n\n```java\nimport com.beagle.api.core.http.Headers;\nimport com.beagle.api.core.http.HttpResponseFor;\nimport com.beagle.api.models.plans.PlanListParams;\nimport com.beagle.api.models.plans.PlanListResponse;\n\nHttpResponseFor plans = client.plans().withRawResponse().list();\n\nint statusCode = plans.statusCode();\nHeaders headers = plans.headers();\n```\n\nYou can still deserialize the response into an instance of a Java class if needed:\n\n```java\nimport com.beagle.api.models.plans.PlanListResponse;\n\nPlanListResponse parsedPlans = plans.parse();\n```\n\n## Error handling\n\nThe SDK throws custom unchecked exception types:\n\n- [`BeagleServiceException`](beagle-java-core/src/main/kotlin/com/beagle/api/errors/BeagleServiceException.kt): Base class for HTTP errors. See this table for which exception subclass is thrown for each HTTP status code:\n\n | Status | Exception |\n | ------ | -------------------------------------------------- |\n | 400 | [`BadRequestException`](beagle-java-core/src/main/kotlin/com/beagle/api/errors/BadRequestException.kt) |\n | 401 | [`UnauthorizedException`](beagle-java-core/src/main/kotlin/com/beagle/api/errors/UnauthorizedException.kt) |\n | 403 | [`PermissionDeniedException`](beagle-java-core/src/main/kotlin/com/beagle/api/errors/PermissionDeniedException.kt) |\n | 404 | [`NotFoundException`](beagle-java-core/src/main/kotlin/com/beagle/api/errors/NotFoundException.kt) |\n | 422 | [`UnprocessableEntityException`](beagle-java-core/src/main/kotlin/com/beagle/api/errors/UnprocessableEntityException.kt) |\n | 429 | [`RateLimitException`](beagle-java-core/src/main/kotlin/com/beagle/api/errors/RateLimitException.kt) |\n | 5xx | [`InternalServerException`](beagle-java-core/src/main/kotlin/com/beagle/api/errors/InternalServerException.kt) |\n | others | [`UnexpectedStatusCodeException`](beagle-java-core/src/main/kotlin/com/beagle/api/errors/UnexpectedStatusCodeException.kt) |\n\n- [`BeagleIoException`](beagle-java-core/src/main/kotlin/com/beagle/api/errors/BeagleIoException.kt): I/O networking errors.\n\n- [`BeagleRetryableException`](beagle-java-core/src/main/kotlin/com/beagle/api/errors/BeagleRetryableException.kt): Generic error indicating a failure that could be retried by the client.\n\n- [`BeagleInvalidDataException`](beagle-java-core/src/main/kotlin/com/beagle/api/errors/BeagleInvalidDataException.kt): Failure to interpret successfully parsed data. For example, when accessing a property that\'s supposed to be required, but the API unexpectedly omitted it from the response.\n\n- [`BeagleException`](beagle-java-core/src/main/kotlin/com/beagle/api/errors/BeagleException.kt): Base class for all exceptions. Most errors will result in one of the previously mentioned ones, but completely generic errors may be thrown using the base class.\n\n\n\n## Logging\n\nEnable logging by setting the `BEAGLE_LOG` environment variable to `info`:\n\n```sh\nexport BEAGLE_LOG=info\n```\n\nOr to `debug` for more verbose logging:\n\n```sh\nexport BEAGLE_LOG=debug\n```\n\nOr configure the client manually using the `logLevel` method:\n\n```java\nimport com.beagle.api.client.BeagleClient;\nimport com.beagle.api.client.okhttp.BeagleOkHttpClient;\nimport com.beagle.api.core.LogLevel;\n\nBeagleClient client = BeagleOkHttpClient.builder()\n .fromEnv()\n .logLevel(LogLevel.INFO)\n .build();\n```\n\n## ProGuard and R8\n\nAlthough the SDK uses reflection, it is still usable with [ProGuard](https://github.com/Guardsquare/proguard) and [R8](https://developer.android.com/topic/performance/app-optimization/enable-app-optimization) because `beagle-java-core` is published with a [configuration file](beagle-java-core/src/main/resources/META-INF/proguard/beagle-java-core.pro) containing [keep rules](https://www.guardsquare.com/manual/configuration/usage).\n\nProGuard and R8 should automatically detect and use the published rules, but you can also manually copy the keep rules if necessary.\n\n\n\n\n\n## Jackson\n\nThe SDK depends on [Jackson](https://github.com/FasterXML/jackson) for JSON serialization/deserialization. It is compatible with version 2.13.4 or higher, but depends on version 2.18.2 by default.\n\nThe SDK throws an exception if it detects an incompatible Jackson version at runtime (e.g. if the default version was overridden in your Maven or Gradle config).\n\nIf the SDK threw an exception, but you\'re _certain_ the version is compatible, then disable the version check using the `checkJacksonVersionCompatibility` on [`BeagleOkHttpClient`](beagle-java-client-okhttp/src/main/kotlin/com/beagle/api/client/okhttp/BeagleOkHttpClient.kt) or [`BeagleOkHttpClientAsync`](beagle-java-client-okhttp/src/main/kotlin/com/beagle/api/client/okhttp/BeagleOkHttpClientAsync.kt).\n\n> [!CAUTION]\n> We make no guarantee that the SDK works correctly when the Jackson version check is disabled.\n\nAlso note that there are bugs in older Jackson versions that can affect the SDK. We don\'t work around all Jackson bugs ([example](https://github.com/FasterXML/jackson-databind/issues/3240)) and expect users to upgrade Jackson for those instead.\n\n## Network options\n\n### Retries\n\nThe SDK automatically retries 2 times by default, with a short exponential backoff between requests.\n\nOnly the following error types are retried:\n- Connection errors (for example, due to a network connectivity problem)\n- 408 Request Timeout\n- 409 Conflict\n- 429 Rate Limit\n- 5xx Internal\n\nThe API may also explicitly instruct the SDK to retry or not retry a request.\n\nTo set a custom number of retries, configure the client using the `maxRetries` method:\n\n```java\nimport com.beagle.api.client.BeagleClient;\nimport com.beagle.api.client.okhttp.BeagleOkHttpClient;\n\nBeagleClient client = BeagleOkHttpClient.builder()\n .fromEnv()\n .maxRetries(4)\n .build();\n```\n\n### Timeouts\n\nRequests time out after 1 minute by default.\n\nTo set a custom timeout, configure the method call using the `timeout` method:\n\n```java\nimport com.beagle.api.models.plans.PlanListResponse;\n\nPlanListResponse plans = client.plans().list(RequestOptions.builder().timeout(Duration.ofSeconds(30)).build());\n```\n\nOr configure the default for all method calls at the client level:\n\n```java\nimport com.beagle.api.client.BeagleClient;\nimport com.beagle.api.client.okhttp.BeagleOkHttpClient;\nimport java.time.Duration;\n\nBeagleClient client = BeagleOkHttpClient.builder()\n .fromEnv()\n .timeout(Duration.ofSeconds(30))\n .build();\n```\n\n### Proxies\n\nTo route requests through a proxy, configure the client using the `proxy` method:\n\n```java\nimport com.beagle.api.client.BeagleClient;\nimport com.beagle.api.client.okhttp.BeagleOkHttpClient;\nimport java.net.InetSocketAddress;\nimport java.net.Proxy;\n\nBeagleClient client = BeagleOkHttpClient.builder()\n .fromEnv()\n .proxy(new Proxy(\n Proxy.Type.HTTP, new InetSocketAddress(\n "https://example.com", 8080\n )\n ))\n .build();\n```\n\nIf the proxy responds with `407 Proxy Authentication Required`, supply credentials by also configuring `proxyAuthenticator`:\n\n```java\nimport com.beagle.api.client.BeagleClient;\nimport com.beagle.api.client.okhttp.BeagleOkHttpClient;\nimport com.beagle.api.core.http.ProxyAuthenticator;\n\nBeagleClient client = BeagleOkHttpClient.builder()\n .fromEnv()\n .proxy(...)\n // Or a custom implementation of `ProxyAuthenticator`.\n .proxyAuthenticator(ProxyAuthenticator.basic("username", "password"))\n .build();\n```\n\n### Connection pooling\n\nTo customize the underlying OkHttp connection pool, configure the client using the `maxIdleConnections` and `keepAliveDuration` methods:\n\n```java\nimport com.beagle.api.client.BeagleClient;\nimport com.beagle.api.client.okhttp.BeagleOkHttpClient;\nimport java.time.Duration;\n\nBeagleClient client = BeagleOkHttpClient.builder()\n .fromEnv()\n // If `maxIdleConnections` is set, then `keepAliveDuration` must be set, and vice versa.\n .maxIdleConnections(10)\n .keepAliveDuration(Duration.ofMinutes(2))\n .build();\n```\n\nIf both options are unset, OkHttp\'s default connection pool settings are used.\n\n### HTTPS\n\n> [!NOTE]\n> Most applications should not call these methods, and instead use the system defaults. The defaults include\n> special optimizations that can be lost if the implementations are modified.\n\nTo configure how HTTPS connections are secured, configure the client using the `sslSocketFactory`, `trustManager`, and `hostnameVerifier` methods:\n\n```java\nimport com.beagle.api.client.BeagleClient;\nimport com.beagle.api.client.okhttp.BeagleOkHttpClient;\n\nBeagleClient client = BeagleOkHttpClient.builder()\n .fromEnv()\n // If `sslSocketFactory` is set, then `trustManager` must be set, and vice versa.\n .sslSocketFactory(yourSSLSocketFactory)\n .trustManager(yourTrustManager)\n .hostnameVerifier(yourHostnameVerifier)\n .build();\n```\n\n### Environments\n\nThe SDK sends requests to the production by default. To send requests to a different environment, configure the client like so:\n\n```java\nimport com.beagle.api.client.BeagleClient;\nimport com.beagle.api.client.okhttp.BeagleOkHttpClient;\n\nBeagleClient client = BeagleOkHttpClient.builder()\n .fromEnv()\n .staging()\n .build();\n```\n\n### Custom HTTP client\n\nThe SDK consists of three artifacts:\n- `beagle-java-core`\n - Contains core SDK logic\n - Does not depend on [OkHttp](https://square.github.io/okhttp)\n - Exposes [`BeagleClient`](beagle-java-core/src/main/kotlin/com/beagle/api/client/BeagleClient.kt), [`BeagleClientAsync`](beagle-java-core/src/main/kotlin/com/beagle/api/client/BeagleClientAsync.kt), [`BeagleClientImpl`](beagle-java-core/src/main/kotlin/com/beagle/api/client/BeagleClientImpl.kt), and [`BeagleClientAsyncImpl`](beagle-java-core/src/main/kotlin/com/beagle/api/client/BeagleClientAsyncImpl.kt), all of which can work with any HTTP client\n- `beagle-java-client-okhttp`\n - Depends on [OkHttp](https://square.github.io/okhttp)\n - Exposes [`BeagleOkHttpClient`](beagle-java-client-okhttp/src/main/kotlin/com/beagle/api/client/okhttp/BeagleOkHttpClient.kt) and [`BeagleOkHttpClientAsync`](beagle-java-client-okhttp/src/main/kotlin/com/beagle/api/client/okhttp/BeagleOkHttpClientAsync.kt), which provide a way to construct [`BeagleClientImpl`](beagle-java-core/src/main/kotlin/com/beagle/api/client/BeagleClientImpl.kt) and [`BeagleClientAsyncImpl`](beagle-java-core/src/main/kotlin/com/beagle/api/client/BeagleClientAsyncImpl.kt), respectively, using OkHttp\n- `beagle-java`\n - Depends on and exposes the APIs of both `beagle-java-core` and `beagle-java-client-okhttp`\n - Does not have its own logic\n\nThis structure allows replacing the SDK\'s default HTTP client without pulling in unnecessary dependencies.\n\n#### Customized [`OkHttpClient`](https://square.github.io/okhttp/3.x/okhttp/okhttp3/OkHttpClient.html)\n\n> [!TIP]\n> Try the available [network options](#network-options) before replacing the default client.\n\nTo use a customized `OkHttpClient`:\n\n1. Replace your [`beagle-java` dependency](#installation) with `beagle-java-core`\n2. Copy `beagle-java-client-okhttp`\'s [`OkHttpClient`](beagle-java-client-okhttp/src/main/kotlin/com/beagle/api/client/okhttp/OkHttpClient.kt) class into your code and customize it\n3. Construct [`BeagleClientImpl`](beagle-java-core/src/main/kotlin/com/beagle/api/client/BeagleClientImpl.kt) or [`BeagleClientAsyncImpl`](beagle-java-core/src/main/kotlin/com/beagle/api/client/BeagleClientAsyncImpl.kt), similarly to [`BeagleOkHttpClient`](beagle-java-client-okhttp/src/main/kotlin/com/beagle/api/client/okhttp/BeagleOkHttpClient.kt) or [`BeagleOkHttpClientAsync`](beagle-java-client-okhttp/src/main/kotlin/com/beagle/api/client/okhttp/BeagleOkHttpClientAsync.kt), using your customized client\n\n### Completely custom HTTP client\n\nTo use a completely custom HTTP client:\n\n1. Replace your [`beagle-java` dependency](#installation) with `beagle-java-core`\n2. Write a class that implements the [`HttpClient`](beagle-java-core/src/main/kotlin/com/beagle/api/core/http/HttpClient.kt) interface\n3. Construct [`BeagleClientImpl`](beagle-java-core/src/main/kotlin/com/beagle/api/client/BeagleClientImpl.kt) or [`BeagleClientAsyncImpl`](beagle-java-core/src/main/kotlin/com/beagle/api/client/BeagleClientAsyncImpl.kt), similarly to [`BeagleOkHttpClient`](beagle-java-client-okhttp/src/main/kotlin/com/beagle/api/client/okhttp/BeagleOkHttpClient.kt) or [`BeagleOkHttpClientAsync`](beagle-java-client-okhttp/src/main/kotlin/com/beagle/api/client/okhttp/BeagleOkHttpClientAsync.kt), using your new client class\n\n## Undocumented API functionality\n\nThe SDK is typed for convenient usage of the documented API. However, it also supports working with undocumented or not yet supported parts of the API.\n\n### Parameters\n\nTo set undocumented parameters, call the `putAdditionalHeader`, `putAdditionalQueryParam`, or `putAdditionalBodyProperty` methods on any `Params` class:\n\n```java\nimport com.beagle.api.core.JsonValue;\nimport com.beagle.api.models.plans.PlanListParams;\n\nPlanListParams params = PlanListParams.builder()\n .putAdditionalHeader("Secret-Header", "42")\n .putAdditionalQueryParam("secret_query_param", "42")\n .putAdditionalBodyProperty("secretProperty", JsonValue.from("42"))\n .build();\n```\n\nThese can be accessed on the built object later using the `_additionalHeaders()`, `_additionalQueryParams()`, and `_additionalBodyProperties()` methods.\n\nTo set undocumented parameters on _nested_ headers, query params, or body classes, call the `putAdditionalProperty` method on the nested class:\n\n```java\nimport com.beagle.api.core.JsonValue;\nimport com.beagle.api.models.tenants.Address;\nimport com.beagle.api.models.tenants.TenantCreateParams;\n\nTenantCreateParams params = TenantCreateParams.builder()\n .address(Address.builder()\n .putAdditionalProperty("secretProperty", JsonValue.from("42"))\n .build())\n .build();\n```\n\nThese properties can be accessed on the nested built object later using the `_additionalProperties()` method.\n\nTo set a documented parameter or property to an undocumented or not yet supported _value_, pass a [`JsonValue`](beagle-java-core/src/main/kotlin/com/beagle/api/core/Values.kt) object to its setter:\n\n```java\nimport com.beagle.api.models.plans.PlanListParams;\n\nPlanListParams params = PlanListParams.builder().build();\n```\n\nThe most straightforward way to create a [`JsonValue`](beagle-java-core/src/main/kotlin/com/beagle/api/core/Values.kt) is using its `from(...)` method:\n\n```java\nimport com.beagle.api.core.JsonValue;\nimport java.util.List;\nimport java.util.Map;\n\n// Create primitive JSON values\nJsonValue nullValue = JsonValue.from(null);\nJsonValue booleanValue = JsonValue.from(true);\nJsonValue numberValue = JsonValue.from(42);\nJsonValue stringValue = JsonValue.from("Hello World!");\n\n// Create a JSON array value equivalent to `["Hello", "World"]`\nJsonValue arrayValue = JsonValue.from(List.of(\n "Hello", "World"\n));\n\n// Create a JSON object value equivalent to `{ "a": 1, "b": 2 }`\nJsonValue objectValue = JsonValue.from(Map.of(\n "a", 1,\n "b", 2\n));\n\n// Create an arbitrarily nested JSON equivalent to:\n// {\n// "a": [1, 2],\n// "b": [3, 4]\n// }\nJsonValue complexValue = JsonValue.from(Map.of(\n "a", List.of(\n 1, 2\n ),\n "b", List.of(\n 3, 4\n )\n));\n```\n\nNormally a `Builder` class\'s `build` method will throw [`IllegalStateException`](https://docs.oracle.com/javase/8/docs/api/java/lang/IllegalStateException.html) if any required parameter or property is unset.\n\nTo forcibly omit a required parameter or property, pass [`JsonMissing`](beagle-java-core/src/main/kotlin/com/beagle/api/core/Values.kt):\n\n```java\nimport com.beagle.api.core.JsonMissing;\nimport com.beagle.api.models.plans.PlanListParams;\nimport com.beagle.api.models.plans.PlanRetrieveParams;\n\nPlanListParams params = PlanRetrieveParams.builder()\n .code(JsonMissing.of())\n .build();\n```\n\n### Response properties\n\nTo access undocumented response properties, call the `_additionalProperties()` method:\n\n```java\nimport com.beagle.api.core.JsonValue;\nimport java.util.Map;\n\nMap additionalProperties = client.plans().list(params)._additionalProperties();\nJsonValue secretPropertyValue = additionalProperties.get("secretProperty");\n\nString result = secretPropertyValue.accept(new JsonValue.Visitor<>() {\n @Override\n public String visitNull() {\n return "It\'s null!";\n }\n\n @Override\n public String visitBoolean(boolean value) {\n return "It\'s a boolean!";\n }\n\n @Override\n public String visitNumber(Number value) {\n return "It\'s a number!";\n }\n\n // Other methods include `visitMissing`, `visitString`, `visitArray`, and `visitObject`\n // The default implementation of each unimplemented method delegates to `visitDefault`, which throws by default, but can also be overridden\n});\n```\n\nTo access a property\'s raw JSON value, which may be undocumented, call its `_` prefixed method:\n\n```java\nimport com.beagle.api.core.JsonField;\nimport java.util.Optional;\n\nJsonField field = client.plans().list(params)._field();\n\nif (field.isMissing()) {\n // The property is absent from the JSON response\n} else if (field.isNull()) {\n // The property was set to literal null\n} else {\n // Check if value was provided as a string\n // Other methods include `asNumber()`, `asBoolean()`, etc.\n Optional jsonString = field.asString();\n\n // Try to deserialize into a custom type\n MyClass myObject = field.asUnknown().orElseThrow().convert(MyClass.class);\n}\n```\n\n### Response validation\n\nIn rare cases, the API may return a response that doesn\'t match the expected type. For example, the SDK may expect a property to contain a `String`, but the API could return something else.\n\nBy default, the SDK will not throw an exception in this case. It will throw [`BeagleInvalidDataException`](beagle-java-core/src/main/kotlin/com/beagle/api/errors/BeagleInvalidDataException.kt) only if you directly access the property.\n\nValidating the response is _not_ forwards compatible with new types from the API for existing fields.\n\nIf you would still prefer to check that the response is completely well-typed upfront, then either call `validate()`:\n\n```java\nimport com.beagle.api.models.plans.PlanListResponse;\n\nPlanListResponse plans = client.plans().list(params).validate();\n```\n\nOr configure the method call to validate the response using the `responseValidation` method:\n\n```java\nimport com.beagle.api.models.plans.PlanListResponse;\n\nPlanListResponse plans = client.plans().list(RequestOptions.builder().responseValidation(true).build());\n```\n\nOr configure the default for all method calls at the client level:\n\n```java\nimport com.beagle.api.client.BeagleClient;\nimport com.beagle.api.client.okhttp.BeagleOkHttpClient;\n\nBeagleClient client = BeagleOkHttpClient.builder()\n .fromEnv()\n .responseValidation(true)\n .build();\n```\n\n## FAQ\n\n### Why don\'t you use plain `enum` classes?\n\nJava `enum` classes are not trivially [forwards compatible](https://www.stainless.com/blog/making-java-enums-forwards-compatible). Using them in the SDK could cause runtime exceptions if the API is updated to respond with a new enum value.\n\n### Why do you represent fields using `JsonField` instead of just plain `T`?\n\nUsing `JsonField` enables a few features:\n\n- Allowing usage of [undocumented API functionality](#undocumented-api-functionality)\n- Lazily [validating the API response against the expected shape](#response-validation)\n- Representing absent vs explicitly null values\n\n### Why don\'t you use [`data` classes](https://kotlinlang.org/docs/data-classes.html)?\n\nIt is not [backwards compatible to add new fields to a data class](https://kotlinlang.org/docs/api-guidelines-backward-compatibility.html#avoid-using-data-classes-in-your-api) and we don\'t want to introduce a breaking change every time we add a field to a class.\n\n### Why don\'t you use checked exceptions?\n\nChecked exceptions are widely considered a mistake in the Java programming language. In fact, they were omitted from Kotlin for this reason.\n\nChecked exceptions:\n\n- Are verbose to handle\n- Encourage error handling at the wrong level of abstraction, where nothing can be done about the error\n- Are tedious to propagate due to the [function coloring problem](https://journal.stuffwithstuff.com/2015/02/01/what-color-is-your-function)\n- Don\'t play well with lambdas (also due to the function coloring problem)\n\n## Semantic versioning\n\nThis package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions:\n\n1. 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.)_\n2. Changes that we do not expect to impact the vast majority of users in practice.\n\nWe take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience.\n\nWe are keen for your feedback; please open an [issue](https://www.github.com/stainless-sdks/beagle-java/issues) with questions, bugs, or suggestions.\n', + }, + { + language: 'python', + content: + '# Beagle Python API library\n\n\n[![PyPI version](https://img.shields.io/pypi/v/beagle.svg?label=pypi%20(stable))](https://pypi.org/project/beagle/)\n\nThe Beagle Python library provides convenient access to the Beagle REST API from any Python 3.9+\napplication. The library includes type definitions for all request params and response fields,\nand offers both synchronous and asynchronous clients powered by [httpx](https://github.com/encode/httpx).\n\n\n\nIt is generated with [Stainless](https://www.stainless.com/).\n\n## MCP Server\n\nUse the Beagle MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application.\n\n[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=%40corgi-tech%2Fbeagle-mcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkBjb3JnaS10ZWNoL2JlYWdsZS1tY3AiXSwiZW52Ijp7IkJFQUdMRV9BUElfS0VZIjoiTXkgQVBJIEtleSJ9fQ)\n[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22%40corgi-tech%2Fbeagle-mcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40corgi-tech%2Fbeagle-mcp%22%5D%2C%22env%22%3A%7B%22BEAGLE_API_KEY%22%3A%22My%20API%20Key%22%7D%7D)\n\n> Note: You may need to set environment variables in your MCP client.\n\n## Documentation\n\n The full API of this library can be found in [api.md](api.md).\n\n## Installation\n\n```sh\n# install from this staging repo\npip install git+ssh://git@github.com/stainless-sdks/beagle-python.git\n```\n> [!NOTE]\n> Once this package is [published to PyPI](https://www.stainless.com/docs/guides/publish), this will become: `pip install beagle`\n\n## Usage\n\nThe full API of this library can be found in [api.md](api.md).\n\n```python\nimport os\nfrom beagle import Beagle\n\nclient = Beagle(\n api_key=os.environ.get("BEAGLE_API_KEY"), # This is the default and can be omitted\n # defaults to "production".\n environment="staging",\n)\n\nplans = client.plans.list()\nprint(plans.data)\n```\n\nWhile you can provide an `api_key` keyword argument,\nwe recommend using [python-dotenv](https://pypi.org/project/python-dotenv/)\nto add `BEAGLE_API_KEY="My API Key"` to your `.env` file\nso that your API Key is not stored in source control.\n\n## Async usage\n\nSimply import `AsyncBeagle` instead of `Beagle` and use `await` with each API call:\n\n```python\nimport os\nimport asyncio\nfrom beagle import AsyncBeagle\n\nclient = AsyncBeagle(\n api_key=os.environ.get("BEAGLE_API_KEY"), # This is the default and can be omitted\n # defaults to "production".\n environment="staging",\n)\n\nasync def main() -> None:\n plans = await client.plans.list()\n print(plans.data)\n\nasyncio.run(main())\n```\n\nFunctionality between the synchronous and asynchronous clients is otherwise identical.\n\n### With aiohttp\n\nBy default, the async client uses `httpx` for HTTP requests. However, for improved concurrency performance you may also use `aiohttp` as the HTTP backend.\n\nYou can enable this by installing `aiohttp`:\n\n```sh\n# install from this staging repo\npip install \'beagle[aiohttp] @ git+ssh://git@github.com/stainless-sdks/beagle-python.git\'\n```\n\nThen you can enable it by instantiating the client with `http_client=DefaultAioHttpClient()`:\n\n```python\nimport os\nimport asyncio\nfrom beagle import DefaultAioHttpClient\nfrom beagle import AsyncBeagle\n\nasync def main() -> None:\n async with AsyncBeagle(\n api_key=os.environ.get("BEAGLE_API_KEY"), # This is the default and can be omitted\n http_client=DefaultAioHttpClient(),\n) as client:\n plans = await client.plans.list()\n print(plans.data)\n\nasyncio.run(main())\n```\n\n\n\n## Using types\n\nNested request parameters are [TypedDicts](https://docs.python.org/3/library/typing.html#typing.TypedDict). Responses are [Pydantic models](https://docs.pydantic.dev) which also provide helper methods for things like:\n\n- Serializing back into JSON, `model.to_json()`\n- Converting to a dictionary, `model.to_dict()`\n\nTyped requests and responses provide autocomplete and documentation within your editor. If you would like to see type errors in VS Code to help catch bugs earlier, set `python.analysis.typeCheckingMode` to `basic`.\n\n\n\n## Nested params\n\nNested parameters are dictionaries, typed using `TypedDict`, for example:\n\n```python\nfrom beagle import Beagle\n\nclient = Beagle()\n\ntenant = client.tenants.create(\n address={\n "city": "South Salt Lake",\n "state": "UT",\n "street1": "123 Main St.",\n "zip": "84115",\n "street2": "Unit 3",\n },\n contact={\n "email": "mark.s@example.com",\n "name": {\n "first": "Mark",\n "last": "Scout",\n },\n },\n property_manager_id=123,\n)\nprint(tenant.address)\n```\n\n\n\n## Handling errors\n\nWhen the library is unable to connect to the API (for example, due to network connection problems or a timeout), a subclass of `beagle.APIConnectionError` is raised.\n\nWhen the API returns a non-success status code (that is, 4xx or 5xx\nresponse), a subclass of `beagle.APIStatusError` is raised, containing `status_code` and `response` properties.\n\nAll errors inherit from `beagle.APIError`.\n\n```python\nimport beagle\nfrom beagle import Beagle\n\nclient = Beagle()\n\ntry:\n client.plans.list()\nexcept beagle.APIConnectionError as e:\n print("The server could not be reached")\n print(e.__cause__) # an underlying Exception, likely raised within httpx.\nexcept beagle.RateLimitError as e:\n print("A 429 status code was received; we should back off a bit.")\nexcept beagle.APIStatusError as e:\n print("Another non-200-range status code was received")\n print(e.status_code)\n print(e.response)\n```\n\nError codes are as follows:\n\n| Status Code | Error Type |\n| ----------- | -------------------------- |\n| 400 | `BadRequestError` |\n| 401 | `AuthenticationError` |\n| 403 | `PermissionDeniedError` |\n| 404 | `NotFoundError` |\n| 422 | `UnprocessableEntityError` |\n| 429 | `RateLimitError` |\n| >=500 | `InternalServerError` |\n| N/A | `APIConnectionError` |\n\n### Retries\n\nCertain errors are automatically retried 2 times by default, with a short exponential backoff.\nConnection errors (for example, due to a network connectivity problem), 408 Request Timeout, 409 Conflict,\n429 Rate Limit, and >=500 Internal errors are all retried by default.\n\nYou can use the `max_retries` option to configure or disable retry settings:\n\n```python\nfrom beagle import Beagle\n\n# Configure the default for all requests:\nclient = Beagle(\n # default is 2\n max_retries=0,\n)\n\n# Or, configure per-request:\nclient.with_options(max_retries = 5).plans.list()\n```\n\n### Timeouts\n\nBy default requests time out after 1 minute. You can configure this with a `timeout` option,\nwhich accepts a float or an [`httpx.Timeout`](https://www.python-httpx.org/advanced/timeouts/#fine-tuning-the-configuration) object:\n\n```python\nfrom beagle import Beagle\n\n# Configure the default for all requests:\nclient = Beagle(\n # 20 seconds (default is 1 minute)\n timeout=20.0,\n)\n\n# More granular control:\nclient = Beagle(\n timeout=httpx.Timeout(60.0, read=5.0, write=10.0, connect=2.0),\n)\n\n# Override per-request:\nclient.with_options(timeout = 5.0).plans.list()\n```\n\nOn timeout, an `APITimeoutError` is thrown.\n\nNote that requests that time out are [retried twice by default](#retries).\n\n\n\n## Advanced\n\n### Logging\n\nWe use the standard library [`logging`](https://docs.python.org/3/library/logging.html) module.\n\nYou can enable logging by setting the environment variable `BEAGLE_LOG` to `info`.\n\n```shell\n$ export BEAGLE_LOG=info\n```\n\nOr to `debug` for more verbose logging.\n\n### How to tell whether `None` means `null` or missing\n\nIn an API response, a field may be explicitly `null`, or missing entirely; in either case, its value is `None` in this library. You can differentiate the two cases with `.model_fields_set`:\n\n```py\nif response.my_field is None:\n if \'my_field\' not in response.model_fields_set:\n print(\'Got json like {}, without a "my_field" key present at all.\')\n else:\n print(\'Got json like {"my_field": null}.\')\n```\n\n### Accessing raw response data (e.g. headers)\n\nThe "raw" Response object can be accessed by prefixing `.with_raw_response.` to any HTTP method call, e.g.,\n\n```py\nfrom beagle import Beagle\n\nclient = Beagle()\nresponse = client.plans.with_raw_response.list()\nprint(response.headers.get(\'X-My-Header\'))\n\nplan = response.parse() # get the object that `plans.list()` would have returned\nprint(plan.data)\n```\n\nThese methods return an [`APIResponse`](https://github.com/stainless-sdks/beagle-python/tree/main/src/beagle/_response.py) object.\n\nThe async client returns an [`AsyncAPIResponse`](https://github.com/stainless-sdks/beagle-python/tree/main/src/beagle/_response.py) with the same structure, the only difference being `await`able methods for reading the response content.\n\n#### `.with_streaming_response`\n\nThe above interface eagerly reads the full response body when you make the request, which may not always be what you want.\n\nTo stream the response body, use `.with_streaming_response` instead, which requires a context manager and only reads the response body once you call `.read()`, `.text()`, `.json()`, `.iter_bytes()`, `.iter_text()`, `.iter_lines()` or `.parse()`. In the async client, these are async methods.\n\n```python\nwith client.plans.with_streaming_response.list() as response :\n print(response.headers.get(\'X-My-Header\'))\n\n for line in response.iter_lines():\n print(line)\n```\n\nThe context manager is required so that the response will reliably be closed.\n\n### Making custom/undocumented requests\n\nThis library is typed for convenient access to the documented API.\n\nIf you need to access undocumented endpoints, params, or response properties, the library can still be used.\n\n#### Undocumented endpoints\n\nTo make requests to undocumented endpoints, you can make requests using `client.get`, `client.post`, and other\nhttp verbs. Options on the client will be respected (such as retries) when making this request.\n\n```py\nimport httpx\n\nresponse = client.post(\n "/foo",\n cast_to=httpx.Response,\n body={"my_param": True},\n)\n\nprint(response.headers.get("x-foo"))\n```\n\n#### Undocumented request params\n\nIf you want to explicitly send an extra param, you can do so with the `extra_query`, `extra_body`, and `extra_headers` request\noptions.\n\n#### Undocumented response properties\n\nTo access undocumented response properties, you can access the extra fields like `response.unknown_prop`. You\ncan also get all the extra fields on the Pydantic model as a dict with\n[`response.model_extra`](https://docs.pydantic.dev/latest/api/base_model/#pydantic.BaseModel.model_extra).\n\n### Configuring the HTTP client\n\nYou can directly override the [httpx client](https://www.python-httpx.org/api/#client) to customize it for your use case, including:\n\n- Support for [proxies](https://www.python-httpx.org/advanced/proxies/)\n- Custom [transports](https://www.python-httpx.org/advanced/transports/)\n- Additional [advanced](https://www.python-httpx.org/advanced/clients/) functionality\n\n```python\nimport httpx\nfrom beagle import Beagle, DefaultHttpxClient\n\nclient = Beagle(\n # Or use the `BEAGLE_BASE_URL` env var\n base_url="http://my.test.server.example.com:8083",\n http_client=DefaultHttpxClient(proxy="http://my.test.proxy.example.com", transport=httpx.HTTPTransport(local_address="0.0.0.0")),\n)\n```\n\nYou can also customize the client on a per-request basis by using `with_options()`:\n\n```python\nclient.with_options(http_client=DefaultHttpxClient(...))\n```\n\n### Managing HTTP resources\n\nBy default the library closes underlying HTTP connections whenever the client is [garbage collected](https://docs.python.org/3/reference/datamodel.html#object.__del__). You can manually close the client using the `.close()` method if desired, or with a context manager that closes when exiting.\n\n```py\nfrom beagle import Beagle\n\nwith Beagle() as client:\n # make requests here\n ...\n\n# HTTP client is now closed\n```\n\n## Versioning\n\nThis package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions:\n\n1. Changes that only affect static types, without breaking runtime behavior.\n2. 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.)_\n3. Changes that we do not expect to impact the vast majority of users in practice.\n\nWe take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience.\n\nWe are keen for your feedback; please open an [issue](https://www.github.com/stainless-sdks/beagle-python/issues) with questions, bugs, or suggestions.\n\n### Determining the installed version\n\nIf you\'ve upgraded to the latest version but aren\'t seeing any new features you were expecting then your python environment is likely still using an older version.\n\nYou can determine the version that is being used at runtime with:\n\n```py\nimport beagle\nprint(beagle.__version__)\n```\n\n## Requirements\n\nPython 3.9 or higher.\n\n## Contributing\n\nSee [the contributing documentation](./CONTRIBUTING.md).\n', + }, + { + language: 'ruby', + content: + '# Beagle Ruby API library\n\nThe Beagle Ruby library provides convenient access to the Beagle REST API from any Ruby 3.2.0+ application. It ships with comprehensive types & docstrings in Yard, RBS, and RBI – [see below](https://github.com/stainless-sdks/beagle-ruby#Sorbet) for usage with Sorbet. The standard library\'s `net/http` is used as the HTTP transport, with connection pooling via the `connection_pool` gem.\n\n\n\nIt is generated with [Stainless](https://www.stainless.com/).\n\n## MCP Server\n\nUse the Beagle MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application.\n\n[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=%40corgi-tech%2Fbeagle-mcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkBjb3JnaS10ZWNoL2JlYWdsZS1tY3AiXSwiZW52Ijp7IkJFQUdMRV9BUElfS0VZIjoiTXkgQVBJIEtleSJ9fQ)\n[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22%40corgi-tech%2Fbeagle-mcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40corgi-tech%2Fbeagle-mcp%22%5D%2C%22env%22%3A%7B%22BEAGLE_API_KEY%22%3A%22My%20API%20Key%22%7D%7D)\n\n> Note: You may need to set environment variables in your MCP client.\n\n## Documentation\n\nDocumentation for releases of this gem can be found [on RubyDoc](https://gemdocs.org/gems/beagle).\n\n\n\n## Installation\n\nTo use this gem, install via Bundler by adding the following to your application\'s `Gemfile`:\n\n```ruby\ngem "beagle", "~> 0.0.1"\n```\n\n## Usage\n\n```ruby\nrequire "bundler/setup"\nrequire "beagle"\n\nbeagle = Beagle::Client.new(\n api_key: ENV["BEAGLE_API_KEY"], # This is the default and can be omitted\n environment: "staging" # defaults to "production"\n)\n\nplans = beagle.plans.list\n\nputs(plans.data)\n```\n\n\n\n\n\n\n\n### Handling errors\n\nWhen 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 `Beagle::Errors::APIError` will be thrown:\n\n```ruby\nbegin\n plan = beagle.plans.list\nrescue Beagle::Errors::APIConnectionError => e\n puts("The server could not be reached")\n puts(e.cause) # an underlying Exception, likely raised within `net/http`\nrescue Beagle::Errors::RateLimitError => e\n puts("A 429 status code was received; we should back off a bit.")\nrescue Beagle::Errors::APIStatusError => e\n puts("Another non-200-range status code was received")\n puts(e.status)\nend\n```\n\nError codes are as follows:\n\n| Cause | Error Type |\n| ---------------- | -------------------------- |\n| HTTP 400 | `BadRequestError` |\n| HTTP 401 | `AuthenticationError` |\n| HTTP 403 | `PermissionDeniedError` |\n| HTTP 404 | `NotFoundError` |\n| HTTP 409 | `ConflictError` |\n| HTTP 422 | `UnprocessableEntityError` |\n| HTTP 429 | `RateLimitError` |\n| HTTP >= 500 | `InternalServerError` |\n| Other HTTP error | `APIStatusError` |\n| Timeout | `APITimeoutError` |\n| Network error | `APIConnectionError` |\n\n### Retries\n\nCertain errors will be automatically retried 2 times by default, with a short exponential backoff.\n\nConnection errors (for example, due to a network connectivity problem), 408 Request Timeout, 409 Conflict, 429 Rate Limit, >=500 Internal errors, and timeouts will all be retried by default.\n\nYou can use the `max_retries` option to configure or disable this:\n\n```ruby\n# Configure the default for all requests:\nbeagle = Beagle::Client.new(\n max_retries: 0 # default is 2\n)\n\n# Or, configure per-request:\nbeagle.plans.list(request_options: {max_retries: 5})\n```\n\n### Timeouts\n\nBy default, requests will time out after 60 seconds. You can use the timeout option to configure or disable this:\n\n```ruby\n# Configure the default for all requests:\nbeagle = Beagle::Client.new(\n timeout: nil # default is 60\n)\n\n# Or, configure per-request:\nbeagle.plans.list(request_options: {timeout: 5})\n```\n\nOn timeout, `Beagle::Errors::APITimeoutError` is raised.\n\nNote that requests that time out are retried by default.\n\n## Advanced concepts\n\n### BaseModel\n\nAll parameter and response objects inherit from `Beagle::Internal::Type::BaseModel`, which provides several conveniences, including:\n\n1. All fields, including unknown ones, are accessible with `obj[:prop]` syntax, and can be destructured with `obj => {prop: prop}` or pattern-matching syntax.\n\n2. Structural equivalence for equality; if two API calls return the same values, comparing the responses with == will return true.\n\n3. Both instances and the classes themselves can be pretty-printed.\n\n4. Helpers such as `#to_h`, `#deep_to_h`, `#to_json`, and `#to_yaml`.\n\n### Making custom or undocumented requests\n\n#### Undocumented properties\n\nYou can send undocumented parameters to any endpoint, and read undocumented response properties, like so:\n\nNote: the `extra_` parameters of the same name overrides the documented parameters.\n\n```ruby\nplans =\n beagle.plans.list(\n request_options: {\n extra_query: {my_query_parameter: value},\n extra_body: {my_body_parameter: value},\n extra_headers: {"my-header": value}\n }\n )\n\nputs(plans[:my_undocumented_property])\n```\n\n#### Undocumented request params\n\nIf you want to explicitly send an extra param, you can do so with the `extra_query`, `extra_body`, and `extra_headers` under the `request_options:` parameter when making a request, as seen in the examples above.\n\n#### Undocumented endpoints\n\nTo make requests to undocumented endpoints while retaining the benefit of auth, retries, and so on, you can make requests using `client.request`, like so:\n\n```ruby\nresponse = client.request(\n method: :post,\n path: \'/undocumented/endpoint\',\n query: {"dog": "woof"},\n headers: {"useful-header": "interesting-value"},\n body: {"hello": "world"}\n)\n```\n\n### Concurrency & connection pooling\n\nThe `Beagle::Client` instances are threadsafe, but are only are fork-safe when there are no in-flight HTTP requests.\n\nEach instance of `Beagle::Client` has its own HTTP connection pool with a default size of 99. As such, we recommend instantiating the client once per application in most settings.\n\nWhen all available connections from the pool are checked out, requests wait for a new connection to become available, with queue time counting towards the request timeout.\n\nUnless otherwise specified, other classes in the SDK do not have locks protecting their underlying data structure.\n\n## Sorbet\n\nThis library provides comprehensive [RBI](https://sorbet.org/docs/rbi) definitions, and has no dependency on sorbet-runtime.\n\nYou can provide typesafe request parameters like so:\n\n```ruby\nbeagle.plans.list \n```\n\nOr, equivalently:\n\n```ruby\n# Hashes work, but are not typesafe:\nbeagle.plans.list\n\n# You can also splat a full Params class:\nparams = Beagle::PlanListParams.new\nbeagle.plans.list(**params)\n```\n\n### Enums\n\nSince this library does not depend on `sorbet-runtime`, it cannot provide [`T::Enum`](https://sorbet.org/docs/tenum) instances. Instead, we provide "tagged symbols" instead, which is always a primitive at runtime:\n\n```ruby\n# :"Premium Paying"\nputs(Beagle::EnrollmentCreateParams::Status::PREMIUM_PAYING)\n\n# Revealed type: `T.all(Beagle::EnrollmentCreateParams::Status, Symbol)`\nT.reveal_type(Beagle::EnrollmentCreateParams::Status::PREMIUM_PAYING)\n```\n\nEnum parameters have a "relaxed" type, so you can either pass in enum constants or their literal value:\n\n```ruby\n# Using the enum constants preserves the tagged type information:\nbeagle.enrollments.create(\n status: Beagle::EnrollmentCreateParams::Status::PREMIUM_PAYING,\n # …\n)\n\n# Literal values are also permissible:\nbeagle.enrollments.create(\n status: :"Premium Paying",\n # …\n)\n```\n\n## Versioning\n\nThis package follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions. As the library is in initial development and has a major version of `0`, APIs may change at any time.\n\nThis package considers improvements to the (non-runtime) `*.rbi` and `*.rbs` type definitions to be non-breaking changes.\n\n## Requirements\n\nRuby 3.2.0 or higher.\n\n## Contributing\n\nSee [the contributing documentation](https://github.com/stainless-sdks/beagle-ruby/tree/main/CONTRIBUTING.md).\n', + }, + { + language: 'typescript', + content: + "# Beagle TypeScript API Library\n\n[![NPM version](https://img.shields.io/npm/v/@corgi-tech/beagle.svg?label=npm%20(stable))](https://npmjs.org/package/@corgi-tech/beagle) ![npm bundle size](https://img.shields.io/bundlephobia/minzip/@corgi-tech/beagle)\n\nThis library provides convenient access to the Beagle REST API from server-side TypeScript or JavaScript.\n\n\n\nThe full API of this library can be found in [api.md](api.md).\n\nIt is generated with [Stainless](https://www.stainless.com/).\n\n## MCP Server\n\nUse the Beagle MCP Server to enable AI assistants to interact with this API, allowing them to explore endpoints, make test requests, and use documentation to help integrate this SDK into your application.\n\n[![Add to Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en-US/install-mcp?name=%40corgi-tech%2Fbeagle-mcp&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIkBjb3JnaS10ZWNoL2JlYWdsZS1tY3AiXSwiZW52Ijp7IkJFQUdMRV9BUElfS0VZIjoiTXkgQVBJIEtleSJ9fQ)\n[![Install in VS Code](https://img.shields.io/badge/_-Add_to_VS_Code-blue?style=for-the-badge&logo=data:image/svg%2bxml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGZpbGw9Im5vbmUiIHZpZXdCb3g9IjAgMCA0MCA0MCI+PHBhdGggZmlsbD0iI0VFRSIgZmlsbC1ydWxlPSJldmVub2RkIiBkPSJNMzAuMjM1IDM5Ljg4NGEyLjQ5MSAyLjQ5MSAwIDAgMS0xLjc4MS0uNzNMMTIuNyAyNC43OGwtMy40NiAyLjYyNC0zLjQwNiAyLjU4MmExLjY2NSAxLjY2NSAwIDAgMS0xLjA4Mi4zMzggMS42NjQgMS42NjQgMCAwIDEtMS4wNDYtLjQzMWwtMi4yLTJhMS42NjYgMS42NjYgMCAwIDEgMC0yLjQ2M0w3LjQ1OCAyMCA0LjY3IDE3LjQ1MyAxLjUwNyAxNC41N2ExLjY2NSAxLjY2NSAwIDAgMSAwLTIuNDYzbDIuMi0yYTEuNjY1IDEuNjY1IDAgMCAxIDIuMTMtLjA5N2w2Ljg2MyA1LjIwOUwyOC40NTIuODQ0YTIuNDg4IDIuNDg4IDAgMCAxIDEuODQxLS43MjljLjM1MS4wMDkuNjk5LjA5MSAxLjAxOS4yNDVsOC4yMzYgMy45NjFhMi41IDIuNSAwIDAgMSAxLjQxNSAyLjI1M3YuMDk5LS4wNDVWMzMuMzd2LS4wNDUuMDk1YTIuNTAxIDIuNTAxIDAgMCAxLTEuNDE2IDIuMjU3bC04LjIzNSAzLjk2MWEyLjQ5MiAyLjQ5MiAwIDAgMS0xLjA3Ny4yNDZabS43MTYtMjguOTQ3LTExLjk0OCA5LjA2MiAxMS45NTIgOS4wNjUtLjAwNC0xOC4xMjdaIi8+PC9zdmc+)](https://vscode.stainless.com/mcp/%7B%22name%22%3A%22%40corgi-tech%2Fbeagle-mcp%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22%40corgi-tech%2Fbeagle-mcp%22%5D%2C%22env%22%3A%7B%22BEAGLE_API_KEY%22%3A%22My%20API%20Key%22%7D%7D)\n\n> Note: You may need to set environment variables in your MCP client.\n\n## Installation\n\n```sh\nnpm install @corgi-tech/beagle\n```\n\n\n\n## Usage\n\nThe full API of this library can be found in [api.md](api.md).\n\n\n```js\nimport Beagle from '@corgi-tech/beagle';\n\nconst client = new Beagle({\n apiKey: process.env['BEAGLE_API_KEY'], // This is the default and can be omitted\n environment: 'staging', // defaults to 'production'\n});\n\nconst plans = await client.plans.list();\n\nconsole.log(plans.data);\n```\n\n\n\n### Request & Response types\n\nThis library includes TypeScript definitions for all request params and response fields. You may import and use them like so:\n\n\n```ts\nimport Beagle from '@corgi-tech/beagle';\n\nconst client = new Beagle({\n apiKey: process.env['BEAGLE_API_KEY'], // This is the default and can be omitted\n environment: 'staging', // defaults to 'production'\n});\n\nconst plans: Beagle.PlanListResponse = await client.plans.list();\n```\n\nDocumentation for each method, request param, and response field are available in docstrings and will appear on hover in most modern editors.\n\n\n\n\n\n## Handling errors\n\nWhen the library is unable to connect to the API,\nor if the API returns a non-success status code (i.e., 4xx or 5xx response),\na subclass of `APIError` will be thrown:\n\n\n```ts\nconst plans = await client.plans.list().catch(async (err) => {\n if (err instanceof Beagle.APIError) {\n console.log(err.status); // 400\n console.log(err.name); // BadRequestError\n console.log(err.headers); // {server: 'nginx', ...}\n } else {\n throw err;\n }\n});\n```\n\nError codes are as follows:\n\n| Status Code | Error Type |\n| ----------- | -------------------------- |\n| 400 | `BadRequestError` |\n| 401 | `AuthenticationError` |\n| 403 | `PermissionDeniedError` |\n| 404 | `NotFoundError` |\n| 422 | `UnprocessableEntityError` |\n| 429 | `RateLimitError` |\n| >=500 | `InternalServerError` |\n| N/A | `APIConnectionError` |\n\n### Retries\n\nCertain errors will be automatically retried 2 times by default, with a short exponential backoff.\nConnection errors (for example, due to a network connectivity problem), 408 Request Timeout, 409 Conflict,\n429 Rate Limit, and >=500 Internal errors will all be retried by default.\n\nYou can use the `maxRetries` option to configure or disable this:\n\n\n```js\n// Configure the default for all requests:\nconst client = new Beagle({\n maxRetries: 0, // default is 2\n});\n\n// Or, configure per-request:\nawait client.plans.list({\n maxRetries: 5,\n});\n```\n\n### Timeouts\n\nRequests time out after 1 minute by default. You can configure this with a `timeout` option:\n\n\n```ts\n// Configure the default for all requests:\nconst client = new Beagle({\n timeout: 20 * 1000, // 20 seconds (default is 1 minute)\n});\n\n// Override per-request:\nawait client.plans.list({\n timeout: 5 * 1000,\n});\n```\n\nOn timeout, an `APIConnectionTimeoutError` is thrown.\n\nNote that requests which time out will be [retried twice by default](#retries).\n\n\n\n\n\n## Advanced Usage\n\n### Accessing raw Response data (e.g., headers)\n\nThe \"raw\" `Response` returned by `fetch()` can be accessed through the `.asResponse()` method on the `APIPromise` type that all methods return.\nThis 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.\n\nYou can also use the `.withResponse()` method to get the raw `Response` along with the parsed data.\nUnlike `.asResponse()` this method consumes the body, returning once it is parsed.\n\n\n```ts\nconst client = new Beagle();\n\nconst response = await client.plans.list().asResponse();\nconsole.log(response.headers.get('X-My-Header'));\nconsole.log(response.statusText); // access the underlying Response object\n\nconst { data: plans, response: raw } = await client.plans.list().withResponse();\nconsole.log(raw.headers.get('X-My-Header'));\nconsole.log(plans.data);\n```\n\n### Logging\n\n> [!IMPORTANT]\n> All log messages are intended for debugging only. The format and content of log messages\n> may change between releases.\n\n#### Log levels\n\nThe log level can be configured in two ways:\n\n1. Via the `BEAGLE_LOG` environment variable\n2. Using the `logLevel` client option (overrides the environment variable if set)\n\n```ts\nimport Beagle from '@corgi-tech/beagle';\n\nconst client = new Beagle({\n logLevel: 'debug', // Show all log messages\n});\n```\n\nAvailable log levels, from most to least verbose:\n\n- `'debug'` - Show debug messages, info, warnings, and errors\n- `'info'` - Show info messages, warnings, and errors\n- `'warn'` - Show warnings and errors (default)\n- `'error'` - Show only errors\n- `'off'` - Disable all logging\n\nAt the `'debug'` level, all HTTP requests and responses are logged, including headers and bodies.\nSome authentication-related headers are redacted, but sensitive data in request and response bodies\nmay still be visible.\n\n#### Custom logger\n\nBy default, this library logs to `globalThis.console`. You can also provide a custom logger.\nMost 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.\n\nWhen providing a custom logger, the `logLevel` option still controls which messages are emitted, messages\nbelow the configured level will not be sent to your logger.\n\n```ts\nimport Beagle from '@corgi-tech/beagle';\nimport pino from 'pino';\n\nconst logger = pino();\n\nconst client = new Beagle({\n logger: logger.child({ name: 'Beagle' }),\n logLevel: 'debug', // Send all messages to pino, allowing it to filter\n});\n```\n\n### Making custom/undocumented requests\n\nThis library is typed for convenient access to the documented API. If you need to access undocumented\nendpoints, params, or response properties, the library can still be used.\n\n#### Undocumented endpoints\n\nTo make requests to undocumented endpoints, you can use `client.get`, `client.post`, and other HTTP verbs.\nOptions on the client, such as retries, will be respected when making these requests.\n\n```ts\nawait client.post('/some/path', {\n body: { some_prop: 'foo' },\n query: { some_query_arg: 'bar' },\n});\n```\n\n#### Undocumented request params\n\nTo make requests using undocumented parameters, you may use `// @ts-expect-error` on the undocumented\nparameter. This library doesn't validate at runtime that the request matches the type, so any extra values you\nsend will be sent as-is.\n\n```ts\nclient.plans.list({\n // ...\n // @ts-expect-error baz is not yet public\n baz: 'undocumented option',\n});\n```\n\nFor requests with the `GET` verb, any extra params will be in the query, all other requests will send the\nextra param in the body.\n\nIf you want to explicitly send an extra argument, you can do so with the `query`, `body`, and `headers` request\noptions.\n\n#### Undocumented response properties\n\nTo access undocumented response properties, you may access the response object with `// @ts-expect-error` on\nthe response object, or cast the response object to the requisite type. Like the request params, we do not\nvalidate or strip extra properties from the response from the API.\n\n### Customizing the fetch client\n\nBy default, this library expects a global `fetch` function is defined.\n\nIf you want to use a different `fetch` function, you can either polyfill the global:\n\n```ts\nimport fetch from 'my-fetch';\n\nglobalThis.fetch = fetch;\n```\n\nOr pass it to the client:\n\n```ts\nimport Beagle from '@corgi-tech/beagle';\nimport fetch from 'my-fetch';\n\nconst client = new Beagle({ fetch });\n```\n\n### Fetch options\n\nIf 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.)\n\n```ts\nimport Beagle from '@corgi-tech/beagle';\n\nconst client = new Beagle({\n fetchOptions: {\n // `RequestInit` options\n },\n});\n```\n\n#### Configuring proxies\n\nTo modify proxy behavior, you can provide custom `fetchOptions` that add runtime-specific proxy\noptions to requests:\n\n **Node** [[docs](https://github.com/nodejs/undici/blob/main/docs/docs/api/ProxyAgent.md#example---proxyagent-with-fetch)]\n\n```ts\nimport Beagle from '@corgi-tech/beagle';\nimport * as undici from 'undici';\n\nconst proxyAgent = new undici.ProxyAgent('http://localhost:8888');\nconst client = new Beagle({\n fetchOptions: {\n dispatcher: proxyAgent,\n },\n});\n```\n\n **Bun** [[docs](https://bun.sh/guides/http/proxy)]\n\n```ts\nimport Beagle from '@corgi-tech/beagle';\n\nconst client = new Beagle({\n fetchOptions: {\n proxy: 'http://localhost:8888',\n },\n});\n```\n\n **Deno** [[docs](https://docs.deno.com/api/deno/~/Deno.createHttpClient)]\n\n```ts\nimport Beagle from 'npm:@corgi-tech/beagle';\n\nconst httpClient = Deno.createHttpClient({ proxy: { url: 'http://localhost:8888' } });\nconst client = new Beagle({\n fetchOptions: {\n client: httpClient,\n },\n});\n```\n\n## Frequently Asked Questions\n\n## Semantic versioning\n\nThis package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions:\n\n1. Changes that only affect static types, without breaking runtime behavior.\n2. 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.)_\n3. Changes that we do not expect to impact the vast majority of users in practice.\n\nWe take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience.\n\nWe are keen for your feedback; please open an [issue](https://www.github.com/corgi-tech/beagle-sdks/issues) with questions, bugs, or suggestions.\n\n## Requirements\n\nTypeScript >= 4.9 is supported.\n\nThe following runtimes are supported:\n\n- Web browsers (Up-to-date Chrome, Firefox, Safari, Edge, and more)\n- Node.js 20 LTS or later ([non-EOL](https://endoflife.date/nodejs)) versions.\n- Deno v1.28.0 or higher.\n- Bun 1.0 or later.\n- Cloudflare Workers.\n- Vercel Edge Runtime.\n- Jest 28 or greater with the `\"node\"` environment (`\"jsdom\"` is not supported at this time).\n- Nitro v2.6 or greater.\n\nNote that React Native is not supported at this time.\n\nIf you are interested in other runtime environments, please open or upvote an issue on GitHub.\n\n## Contributing\n\nSee [the contributing documentation](./CONTRIBUTING.md).\n", + }, +]; + +const INDEX_OPTIONS = { + fields: [ + 'name', + 'endpoint', + 'summary', + 'description', + 'qualified', + 'stainlessPath', + 'content', + 'sectionContext', + ], + storeFields: ['kind', '_original'], + searchOptions: { + prefix: true, + fuzzy: 0.1, + boost: { + name: 5, + stainlessPath: 3, + endpoint: 3, + qualified: 3, + summary: 2, + content: 1, + description: 1, + } as Record, + }, +}; + +/** + * Self-contained local search engine backed by MiniSearch. + * Method data is embedded at SDK build time; prose documents + * can be loaded from an optional docs directory at runtime. + */ +export class LocalDocsSearch { + private methodIndex: MiniSearch; + private proseIndex: MiniSearch; + + private constructor() { + this.methodIndex = new MiniSearch(INDEX_OPTIONS); + this.proseIndex = new MiniSearch(INDEX_OPTIONS); + } + + static async create(opts?: { docsDir?: string }): Promise { + const instance = new LocalDocsSearch(); + instance.indexMethods(EMBEDDED_METHODS); + for (const readme of EMBEDDED_READMES) { + instance.indexProse(readme.content, `readme:${readme.language}`); + } + if (opts?.docsDir) { + await instance.loadDocsDirectory(opts.docsDir); + } + return instance; + } + + search(props: { + query: string; + language?: string; + detail?: string; + maxResults?: number; + maxLength?: number; + }): SearchResult { + const { query, language = 'typescript', detail = 'default', maxResults = 5, maxLength = 100_000 } = props; + + const useMarkdown = detail === 'verbose' || detail === 'high'; + + // Search both indices and merge results by score. + // Filter prose hits so language-tagged content (READMEs and docs with + // frontmatter) only matches the requested language. + const methodHits = this.methodIndex + .search(query) + .map((hit) => ({ ...hit, _kind: 'http_method' as const })); + const proseHits = this.proseIndex + .search(query) + .filter((hit) => { + const source = ((hit as Record)['_original'] as ProseChunk | undefined)?.source; + if (!source) return true; + // Check for language-tagged sources: "readme:" or "lang::" + let taggedLang: string | undefined; + if (source.startsWith('readme:')) taggedLang = source.slice('readme:'.length); + else if (source.startsWith('lang:')) taggedLang = source.split(':')[1]; + if (!taggedLang) return true; + return taggedLang === language || (language === 'javascript' && taggedLang === 'typescript'); + }) + .map((hit) => ({ ...hit, _kind: 'prose' as const })); + const merged = [...methodHits, ...proseHits].sort((a, b) => b.score - a.score); + const top = merged.slice(0, maxResults); + + const fullResults: (string | Record)[] = []; + + for (const hit of top) { + const original = (hit as Record)['_original']; + if (hit._kind === 'http_method') { + const m = original as MethodEntry; + if (useMarkdown && m.markdown) { + fullResults.push(m.markdown); + } else { + // Use per-language data when available, falling back to the + // top-level fields (which are TypeScript-specific in the + // legacy codepath). + const langData = m.perLanguage?.[language]; + fullResults.push({ + method: langData?.method ?? m.qualified, + summary: m.summary, + description: m.description, + endpoint: `${m.httpMethod.toUpperCase()} ${m.endpoint}`, + ...(langData?.example ? { example: langData.example } : {}), + ...(m.params ? { params: m.params } : {}), + ...(m.response ? { response: m.response } : {}), + }); + } + } else { + const c = original as ProseChunk; + fullResults.push({ + content: c.content, + ...(c.source ? { source: c.source } : {}), + }); + } + } + + let totalLength = 0; + const results: (string | Record)[] = []; + for (const result of fullResults) { + const len = typeof result === 'string' ? result.length : JSON.stringify(result).length; + totalLength += len; + if (totalLength > maxLength) break; + results.push(result); + } + + if (results.length < fullResults.length) { + results.unshift(`Truncated; showing ${results.length} of ${fullResults.length} results.`); + } + + return { results }; + } + + private indexMethods(methods: MethodEntry[]): void { + const docs: MiniSearchDocument[] = methods.map((m, i) => ({ + id: `method-${i}`, + kind: 'http_method' as const, + name: m.name, + endpoint: m.endpoint, + summary: m.summary, + description: m.description, + qualified: m.qualified, + stainlessPath: m.stainlessPath, + _original: m as unknown as Record, + })); + if (docs.length > 0) { + this.methodIndex.addAll(docs); + } + } + + private async loadDocsDirectory(docsDir: string): Promise { + let entries; + try { + entries = await fs.readdir(docsDir, { withFileTypes: true }); + } catch (err) { + getLogger().warn({ err, docsDir }, 'Could not read docs directory'); + return; + } + + const files = entries + .filter((e) => e.isFile()) + .filter((e) => e.name.endsWith('.md') || e.name.endsWith('.markdown') || e.name.endsWith('.json')); + + for (const file of files) { + try { + const filePath = path.join(docsDir, file.name); + const content = await fs.readFile(filePath, 'utf-8'); + + if (file.name.endsWith('.json')) { + const texts = extractTexts(JSON.parse(content)); + if (texts.length > 0) { + this.indexProse(texts.join('\n\n'), file.name); + } + } else { + // Parse optional YAML frontmatter for language tagging. + // Files with a "language" field in frontmatter will only + // surface in searches for that language. + // + // Example: + // --- + // language: python + // --- + // # Error handling in Python + // ... + const frontmatter = parseFrontmatter(content); + const source = frontmatter.language ? `lang:${frontmatter.language}:${file.name}` : file.name; + this.indexProse(content, source); + } + } catch (err) { + getLogger().warn({ err, file: file.name }, 'Failed to index docs file'); + } + } + } + + private indexProse(markdown: string, source: string): void { + const chunks = chunkMarkdown(markdown); + const baseId = this.proseIndex.documentCount; + + const docs: MiniSearchDocument[] = chunks.map((chunk, i) => ({ + id: `prose-${baseId + i}`, + kind: 'prose' as const, + content: chunk.content, + ...(chunk.sectionContext != null ? { sectionContext: chunk.sectionContext } : {}), + _original: { ...chunk, source } as unknown as Record, + })); + + if (docs.length > 0) { + this.proseIndex.addAll(docs); + } + } +} + +/** Lightweight markdown chunker — splits on headers, chunks by word count. */ +function chunkMarkdown(markdown: string): { content: string; tag: string; sectionContext?: string }[] { + // Strip YAML frontmatter + const stripped = markdown.replace(/^---\n[\s\S]*?\n---\n?/, ''); + const lines = stripped.split('\n'); + + const chunks: { content: string; tag: string; sectionContext?: string }[] = []; + const headers: string[] = []; + let current: string[] = []; + + const flush = () => { + const text = current.join('\n').trim(); + if (!text) return; + const sectionContext = headers.length > 0 ? headers.join(' > ') : undefined; + // Split into ~200-word chunks + const words = text.split(/\s+/); + for (let i = 0; i < words.length; i += 200) { + const slice = words.slice(i, i + 200).join(' '); + if (slice) { + chunks.push({ content: slice, tag: 'p', ...(sectionContext != null ? { sectionContext } : {}) }); + } + } + current = []; + }; + + for (const line of lines) { + const headerMatch = line.match(/^(#{1,6})\s+(.+)/); + if (headerMatch) { + flush(); + const level = headerMatch[1]!.length; + const text = headerMatch[2]!.trim(); + while (headers.length >= level) headers.pop(); + headers.push(text); + } else { + current.push(line); + } + } + flush(); + + return chunks; +} + +/** Recursively extracts string values from a JSON structure. */ +function extractTexts(data: unknown, depth = 0): string[] { + if (depth > 10) return []; + if (typeof data === 'string') return data.trim() ? [data] : []; + if (Array.isArray(data)) return data.flatMap((item) => extractTexts(item, depth + 1)); + if (typeof data === 'object' && data !== null) { + return Object.values(data).flatMap((v) => extractTexts(v, depth + 1)); + } + return []; +} + +/** Parses YAML frontmatter from a markdown string, extracting the language field if present. */ +function parseFrontmatter(markdown: string): { language?: string } { + const match = markdown.match(/^---\n([\s\S]*?)\n---/); + if (!match) return {}; + const body = match[1] ?? ''; + const langMatch = body.match(/^language:\s*(.+)$/m); + return langMatch ? { language: langMatch[1]!.trim() } : {}; +} diff --git a/packages/mcp-server/src/logger.ts b/packages/mcp-server/src/logger.ts new file mode 100644 index 00000000..29dab11c --- /dev/null +++ b/packages/mcp-server/src/logger.ts @@ -0,0 +1,28 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { pino, type Level, type Logger } from 'pino'; +import pretty from 'pino-pretty'; + +let _logger: Logger | undefined; + +export function configureLogger({ level, pretty: usePretty }: { level: Level; pretty: boolean }): void { + _logger = pino( + { + level, + timestamp: pino.stdTimeFunctions.isoTime, + formatters: { + level(label) { + return { level: label }; + }, + }, + }, + usePretty ? pretty({ colorize: true, levelFirst: true, destination: 2 }) : process.stderr, + ); +} + +export function getLogger(): Logger { + if (!_logger) { + throw new Error('Logger has not been configured. Call configureLogger() before using the logger.'); + } + return _logger; +} diff --git a/packages/mcp-server/src/methods.ts b/packages/mcp-server/src/methods.ts new file mode 100644 index 00000000..90d52067 --- /dev/null +++ b/packages/mcp-server/src/methods.ts @@ -0,0 +1,194 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { McpOptions } from './options'; + +export type SdkMethod = { + clientCallName: string; + fullyQualifiedName: string; + httpMethod?: 'get' | 'post' | 'put' | 'patch' | 'delete' | 'query'; + httpPath?: string; +}; + +export const sdkMethods: SdkMethod[] = [ + { + clientCallName: 'client.plans.retrieve', + fullyQualifiedName: 'plans.retrieve', + httpMethod: 'get', + httpPath: '/api/plans/{code}', + }, + { + clientCallName: 'client.plans.list', + fullyQualifiedName: 'plans.list', + httpMethod: 'get', + httpPath: '/api/plans', + }, + { + clientCallName: 'client.propertyManagers.create', + fullyQualifiedName: 'propertyManagers.create', + httpMethod: 'post', + httpPath: '/api/property-managers', + }, + { + clientCallName: 'client.propertyManagers.retrieve', + fullyQualifiedName: 'propertyManagers.retrieve', + httpMethod: 'get', + httpPath: '/api/property-managers/{id}', + }, + { + clientCallName: 'client.propertyManagers.update', + fullyQualifiedName: 'propertyManagers.update', + httpMethod: 'patch', + httpPath: '/api/property-managers/{id}', + }, + { + clientCallName: 'client.propertyManagers.list', + fullyQualifiedName: 'propertyManagers.list', + httpMethod: 'get', + httpPath: '/api/property-managers', + }, + { + clientCallName: 'client.propertyManagers.delete', + fullyQualifiedName: 'propertyManagers.delete', + httpMethod: 'delete', + httpPath: '/api/property-managers/{id}', + }, + { + clientCallName: 'client.tenants.create', + fullyQualifiedName: 'tenants.create', + httpMethod: 'post', + httpPath: '/api/tenants', + }, + { + clientCallName: 'client.tenants.retrieve', + fullyQualifiedName: 'tenants.retrieve', + httpMethod: 'get', + httpPath: '/api/tenants/{id}', + }, + { + clientCallName: 'client.tenants.update', + fullyQualifiedName: 'tenants.update', + httpMethod: 'patch', + httpPath: '/api/tenants/{id}', + }, + { + clientCallName: 'client.tenants.list', + fullyQualifiedName: 'tenants.list', + httpMethod: 'get', + httpPath: '/api/tenants', + }, + { + clientCallName: 'client.tenants.delete', + fullyQualifiedName: 'tenants.delete', + httpMethod: 'delete', + httpPath: '/api/tenants/{id}', + }, + { + clientCallName: 'client.enrollments.create', + fullyQualifiedName: 'enrollments.create', + httpMethod: 'post', + httpPath: '/api/enrollments', + }, + { + clientCallName: 'client.enrollments.retrieve', + fullyQualifiedName: 'enrollments.retrieve', + httpMethod: 'get', + httpPath: '/api/enrollments/{id}', + }, + { + clientCallName: 'client.enrollments.list', + fullyQualifiedName: 'enrollments.list', + httpMethod: 'get', + httpPath: '/api/enrollments', + }, + { + clientCallName: 'client.enrollments.lapse', + fullyQualifiedName: 'enrollments.lapse', + httpMethod: 'delete', + httpPath: '/api/enrollments/{id}', + }, + { + clientCallName: 'client.enrollments.retrieveCertificate', + fullyQualifiedName: 'enrollments.retrieveCertificate', + httpMethod: 'get', + httpPath: '/api/enrollments/{id}/certificate', + }, + { + clientCallName: 'client.insuranceVerification.verify', + fullyQualifiedName: 'insuranceVerification.verify', + httpMethod: 'post', + httpPath: '/api/insurance-verification', + }, +]; + +function allowedMethodsForCodeTool(options: McpOptions | undefined): SdkMethod[] | undefined { + if (!options) { + return undefined; + } + + let allowedMethods: SdkMethod[]; + + if (options.codeAllowHttpGets || options.codeAllowedMethods) { + // Start with nothing allowed and then add into it from options + let allowedMethodsSet = new Set(); + + if (options.codeAllowHttpGets) { + // Add all methods that map to an HTTP GET + sdkMethods + .filter((method) => method.httpMethod === 'get') + .forEach((method) => allowedMethodsSet.add(method)); + } + + if (options.codeAllowedMethods) { + // Add all methods that match any of the allowed regexps + const allowedRegexps = options.codeAllowedMethods.map((pattern) => { + try { + return new RegExp(pattern); + } catch (e) { + throw new Error( + `Invalid regex pattern for allowed method: "${pattern}": ${e instanceof Error ? e.message : e}`, + ); + } + }); + + sdkMethods + .filter((method) => allowedRegexps.some((regexp) => regexp.test(method.fullyQualifiedName))) + .forEach((method) => allowedMethodsSet.add(method)); + } + + allowedMethods = Array.from(allowedMethodsSet); + } else { + // Start with everything allowed + allowedMethods = [...sdkMethods]; + } + + if (options.codeBlockedMethods) { + // Filter down based on blocked regexps + const blockedRegexps = options.codeBlockedMethods.map((pattern) => { + try { + return new RegExp(pattern); + } catch (e) { + throw new Error( + `Invalid regex pattern for blocked method: "${pattern}": ${e instanceof Error ? e.message : e}`, + ); + } + }); + + allowedMethods = allowedMethods.filter( + (method) => !blockedRegexps.some((regexp) => regexp.test(method.fullyQualifiedName)), + ); + } + + return allowedMethods; +} + +export function blockedMethodsForCodeTool(options: McpOptions | undefined): SdkMethod[] | undefined { + const allowedMethods = allowedMethodsForCodeTool(options); + if (!allowedMethods) { + return undefined; + } + + const allowedSet = new Set(allowedMethods.map((method) => method.fullyQualifiedName)); + + // Return any methods that are not explicitly allowed + return sdkMethods.filter((method) => !allowedSet.has(method.fullyQualifiedName)); +} diff --git a/packages/mcp-server/src/options.ts b/packages/mcp-server/src/options.ts index c0751018..f1518764 100644 --- a/packages/mcp-server/src/options.ts +++ b/packages/mcp-server/src/options.ts @@ -1,319 +1,185 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import qs from 'qs'; import yargs from 'yargs'; import { hideBin } from 'yargs/helpers'; -import { endpoints, Filter } from './tools'; -import { ClientCapabilities, knownClients, ClientType } from './compat'; +import z from 'zod'; +import { readEnv } from './util'; export type CLIOptions = McpOptions & { - list: boolean; + debug: boolean; + logFormat: 'json' | 'pretty'; + transport: 'stdio' | 'http'; + port: number | undefined; + socket: string | undefined; }; export type McpOptions = { - client: ClientType | undefined; - includeDynamicTools: boolean | undefined; - includeAllTools: boolean | undefined; - filters: Filter[]; - capabilities?: Partial; + includeCodeTool?: boolean | undefined; + includeDocsTools?: boolean | undefined; + stainlessApiKey?: string | undefined; + docsSearchMode?: 'stainless-api' | 'local' | undefined; + docsDir?: string | undefined; + codeAllowHttpGets?: boolean | undefined; + codeAllowedMethods?: string[] | undefined; + codeBlockedMethods?: string[] | undefined; + codeExecutionMode: McpCodeExecutionMode; + customInstructionsPath?: string | undefined; }; -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 type McpCodeExecutionMode = 'stainless-sandbox' | 'local'; -export function parseOptions(): CLIOptions { +export function parseCLIOptions(): CLIOptions { const opts = yargs(hideBin(process.argv)) - .option('tools', { - type: 'string', - array: true, - choices: ['dynamic', 'all'], - description: 'Use dynamic tools or all tools', + .option('code-allow-http-gets', { + type: 'boolean', + description: + 'Allow all code tool methods that map to HTTP GET operations. If all code-allow-* flags are unset, then everything is allowed.', }) - .option('no-tools', { + .option('code-allowed-methods', { type: 'string', array: true, - choices: ['dynamic', 'all'], - description: 'Do not use any dynamic or all tools', + description: + 'Methods to explicitly allow for code tool. Evaluated as regular expressions against method fully qualified names. If all code-allow-* flags are unset, then everything is allowed.', }) - .option('tool', { + .option('code-blocked-methods', { type: 'string', array: true, - description: 'Include tools matching the specified names', + description: + 'Methods to explicitly block for code tool. Evaluated as regular expressions against method fully qualified names. If all code-allow-* flags are unset, then everything is allowed.', }) - .option('resource', { + .option('code-execution-mode', { type: 'string', - array: true, - description: 'Include tools matching the specified resources', + choices: ['stainless-sandbox', 'local'], + default: 'stainless-sandbox', + description: + "Where to run code execution in code tool; 'stainless-sandbox' will execute code in Stainless-hosted sandboxes whereas 'local' will execute code locally on the MCP server machine.", }) - .option('operation', { + .option('custom-instructions-path', { type: 'string', - array: true, - choices: ['read', 'write'], - description: 'Include tools matching the specified operations', + description: 'Path to custom instructions for the MCP server', }) - .option('tag', { + .option('debug', { type: 'boolean', description: 'Enable debug logging' }) + .option('docs-dir', { type: 'string', - array: true, - description: 'Include tools with the specified tags', + description: + 'Path to a directory of local documentation files (markdown/JSON) to include in local docs search.', }) - .option('no-tool', { + .option('docs-search-mode', { type: 'string', - array: true, - description: 'Exclude tools matching the specified names', + choices: ['stainless-api', 'local'], + default: 'stainless-api', + description: + "Where to search documentation; 'stainless-api' uses the Stainless-hosted search API whereas 'local' uses an in-memory search index built from embedded SDK method data and optional local docs files.", }) - .option('no-resource', { + .option('log-format', { type: 'string', - array: true, - description: 'Exclude tools matching the specified resources', + choices: ['json', 'pretty'], + description: 'Format for log output; defaults to json unless tty is detected', }) - .option('no-operation', { + .option('no-tools', { type: 'string', array: true, - description: 'Exclude tools matching the specified operations', + choices: ['code', 'docs'], + description: 'Tools to explicitly disable', }) - .option('no-tag', { - type: 'string', - array: true, - description: 'Exclude tools with the specified tags', + .option('port', { + type: 'number', + default: 3000, + description: 'Port to serve on if using http transport', }) - .option('list', { - type: 'boolean', - description: 'List all tools and exit', - }) - .option('client', { + .option('socket', { type: 'string', description: 'Unix socket to serve on if using http transport' }) + .option('stainless-api-key', { type: 'string', - choices: Object.keys(knownClients), - description: 'Specify the MCP client being used', + default: readEnv('STAINLESS_API_KEY'), + description: + 'API key for Stainless. Used to authenticate requests to Stainless-hosted tools endpoints.', }) - .option('capability', { + .option('tools', { type: 'string', array: true, - description: 'Specify client capabilities', - coerce: (values: string[]) => { - return values.flatMap((v) => v.split(',')); - }, + choices: ['code', 'docs'], + description: 'Tools to explicitly enable', }) - .option('no-capability', { + .option('transport', { 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', + choices: ['stdio', 'http'], + default: 'stdio', + description: 'What transport to use; stdio for local servers or http for remote servers', }) + .env('MCP_SERVER') + .version(true) .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(',')); - }; + const shouldIncludeToolType = (toolType: 'code' | 'docs') => + argv.noTools?.includes(toolType) ? false + : argv.tools?.includes(toolType) ? true + : undefined; - for (const tag of splitValues(argv.tag)) { - filters.push({ type: 'tag', op: 'include', value: tag }); - } + const includeCodeTool = shouldIncludeToolType('code'); + const includeDocsTools = shouldIncludeToolType('docs'); - for (const tag of splitValues(argv.noTag)) { - filters.push({ type: 'tag', op: 'exclude', value: tag }); - } + const transport = argv.transport as 'stdio' | 'http'; + const logFormat = + argv.logFormat ? (argv.logFormat as 'json' | 'pretty') + : process.stderr.isTTY ? 'pretty' + : 'json'; - 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 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; - - const client = argv.client as ClientType; return { - client: client && knownClients[client] ? client : undefined, - includeDynamicTools, - includeAllTools, - filters, - capabilities: clientCapabilities, - list: argv.list || false, + ...(includeCodeTool !== undefined && { includeCodeTool }), + ...(includeDocsTools !== undefined && { includeDocsTools }), + debug: !!argv.debug, + stainlessApiKey: argv.stainlessApiKey, + docsSearchMode: argv.docsSearchMode as 'stainless-api' | 'local' | undefined, + docsDir: argv.docsDir, + codeAllowHttpGets: argv.codeAllowHttpGets, + codeAllowedMethods: argv.codeAllowedMethods, + codeBlockedMethods: argv.codeBlockedMethods, + codeExecutionMode: argv.codeExecutionMode as McpCodeExecutionMode, + customInstructionsPath: argv.customInstructionsPath, + transport, + logFormat, + port: argv.port, + socket: argv.socket, }; } -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(knownClients, 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; +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(['code', 'docs'])).describe('Specify which MCP tools to use'), + no_tools: coerceArray(z.enum(['code', 'docs'])).describe('Specify which MCP tools to not use.'), + tool: coerceArray(z.string()).describe('Include tools matching the specified names'), +}); + +export function parseQueryOptions(defaultOptions: McpOptions, query: unknown): McpOptions { + const queryObject = typeof query === 'string' ? qs.parse(query) : query; + const queryOptions = QueryOptions.parse(queryObject); + + let codeTool: boolean | undefined = + queryOptions.no_tools && queryOptions.no_tools?.includes('code') ? false + : queryOptions.tools?.includes('code') ? true + : defaultOptions.includeCodeTool; + + let docsTools: boolean | undefined = + queryOptions.no_tools && queryOptions.no_tools?.includes('docs') ? false + : queryOptions.tools?.includes('docs') ? true + : defaultOptions.includeDocsTools; - 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]] : []), - ]; + return { + ...(codeTool !== undefined && { includeCodeTool: codeTool }), + ...(docsTools !== undefined && { includeDocsTools: docsTools }), + codeExecutionMode: defaultOptions.codeExecutionMode, + docsSearchMode: defaultOptions.docsSearchMode, + docsDir: defaultOptions.docsDir, + }; } diff --git a/packages/mcp-server/src/server.ts b/packages/mcp-server/src/server.ts index eb90312a..a503c5b6 100644 --- a/packages/mcp-server/src/server.ts +++ b/packages/mcp-server/src/server.ts @@ -2,149 +2,209 @@ 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 'beagle'; -import Beagle from 'beagle'; import { - applyCompatibilityTransformations, - ClientCapabilities, - defaultClientCapabilities, - knownClients, - parseEmbeddedJSON, -} from './compat'; -import { dynamicTools } from './dynamic-tools'; + CallToolRequestSchema, + ListToolsRequestSchema, + SetLevelRequestSchema, +} from '@modelcontextprotocol/sdk/types.js'; +import { ClientOptions } from '@corgi-tech/beagle'; +import Beagle from '@corgi-tech/beagle'; +import { codeTool } from './code-tool'; +import docsSearchTool from './docs-search-tool'; +import { setLocalSearch } from './docs-search-tool'; +import { LocalDocsSearch } from './local-docs-search'; +import { getInstructions } from './instructions'; import { McpOptions } from './options'; - -export { McpOptions } from './options'; -export { ClientType } from './compat'; -export { Filter } from './tools'; -export { ClientOptions } from 'beagle'; -export { endpoints } from './tools'; - -// Create server instance -export const server = new McpServer( - { - name: 'beagle_api', - version: '0.0.1-alpha.0', - }, - { - capabilities: { - tools: {}, +import { blockedMethodsForCodeTool } from './methods'; +import { HandlerFunction, McpRequestContext, ToolCallResult, McpTool } from './types'; +import { readEnv } from './util'; + +export const newMcpServer = async ({ + stainlessApiKey, + customInstructionsPath, +}: { + stainlessApiKey?: string | undefined; + customInstructionsPath?: string | undefined; +}) => + new McpServer( + { + name: 'corgi_tech_beagle_api', + version: '2.0.0', + }, + { + instructions: await getInstructions({ stainlessApiKey, customInstructionsPath }), + capabilities: { tools: {}, logging: {} }, }, - }, -); + ); /** * 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: { +export async function initMcpServer(params: { server: Server | McpServer; - clientOptions: ClientOptions; - mcpOptions: McpOptions; - endpoints?: { tool: Tool; handler: HandlerFunction }[]; + clientOptions?: ClientOptions; + mcpOptions?: McpOptions; + stainlessApiKey?: string | undefined; + upstreamClientEnvs?: Record | undefined; + mcpSessionId?: string | undefined; + mcpClientInfo?: { name: string; version: string } | undefined; }) { - const transformedEndpoints = selectTools(endpoints, params.mcpOptions); - const client = new Beagle(params.clientOptions); - const capabilities = { - ...defaultClientCapabilities, - ...(params.mcpOptions.client ? knownClients[params.mcpOptions.client] : params.mcpOptions.capabilities), + const server = params.server instanceof McpServer ? params.server.server : params.server; + + const logAtLevel = + (level: 'debug' | 'info' | 'warning' | 'error') => + (message: string, ...rest: unknown[]) => { + void server.sendLoggingMessage({ + level, + data: { message, rest }, + }); + }; + const logger = { + debug: logAtLevel('debug'), + info: logAtLevel('info'), + warn: logAtLevel('warning'), + error: logAtLevel('error'), }; - init({ server: params.server, client, endpoints: transformedEndpoints, capabilities }); -} -export function init(params: { - server: Server | McpServer; - client?: Beagle; - endpoints?: { tool: Tool; handler: HandlerFunction }[]; - capabilities?: Partial; -}) { - const server = params.server instanceof McpServer ? params.server.server : params.server; - const providedEndpoints = params.endpoints || endpoints; + if (params.mcpOptions?.docsSearchMode === 'local') { + const docsDir = params.mcpOptions?.docsDir; + const localSearch = await LocalDocsSearch.create(docsDir ? { docsDir } : undefined); + setLocalSearch(localSearch); + } - const endpointMap = Object.fromEntries(providedEndpoints.map((endpoint) => [endpoint.tool.name, endpoint])); + let _client: Beagle | undefined; + let _clientError: Error | undefined; + let _logLevel: 'debug' | 'info' | 'warn' | 'error' | 'off' | undefined; + + const getClient = (): Beagle => { + if (_clientError) throw _clientError; + if (!_client) { + try { + _client = new Beagle({ + ...{ environment: (readEnv('BEAGLE_ENVIRONMENT') || undefined) as any }, + logger, + ...params.clientOptions, + defaultHeaders: { + ...params.clientOptions?.defaultHeaders, + 'X-Stainless-MCP': 'true', + }, + }); + if (_logLevel) { + _client = _client.withOptions({ logLevel: _logLevel }); + } + } catch (e) { + _clientError = e instanceof Error ? e : new Error(String(e)); + throw _clientError; + } + } + return _client; + }; - const client = - params.client || - new Beagle({ - environment: (readEnv('BEAGLE_ENVIRONMENT') || undefined) as any, - defaultHeaders: { 'X-Stainless-MCP': 'true' }, - }); + const providedTools = selectTools(params.mcpOptions); + const toolMap = Object.fromEntries(providedTools.map((mcpTool) => [mcpTool.tool.name, mcpTool])); server.setRequestHandler(ListToolsRequestSchema, async () => { return { - tools: providedEndpoints.map((endpoint) => endpoint.tool), + tools: providedTools.map((mcpTool) => mcpTool.tool), }; }); server.setRequestHandler(CallToolRequestSchema, async (request) => { const { name, arguments: args } = request.params; - const endpoint = endpointMap[name]; - if (!endpoint) { + const mcpTool = toolMap[name]; + if (!mcpTool) { throw new Error(`Unknown tool: ${name}`); } - return executeHandler(endpoint.tool, endpoint.handler, client, args, params.capabilities); + let client: Beagle; + try { + client = getClient(); + } catch (error) { + return { + content: [ + { + type: 'text' as const, + text: `Failed to initialize client: ${error instanceof Error ? error.message : String(error)}`, + }, + ], + isError: true, + }; + } + + return executeHandler({ + handler: mcpTool.handler, + reqContext: { + client, + stainlessApiKey: params.stainlessApiKey ?? params.mcpOptions?.stainlessApiKey, + upstreamClientEnvs: params.upstreamClientEnvs, + mcpSessionId: params.mcpSessionId, + mcpClientInfo: params.mcpClientInfo, + }, + args, + }); + }); + + server.setRequestHandler(SetLevelRequestSchema, async (request) => { + const { level } = request.params; + let logLevel: 'debug' | 'info' | 'warn' | 'error' | 'off'; + switch (level) { + case 'debug': + logLevel = 'debug'; + break; + case 'info': + logLevel = 'info'; + break; + case 'notice': + case 'warning': + logLevel = 'warn'; + break; + case 'error': + logLevel = 'error'; + break; + default: + logLevel = 'off'; + break; + } + _logLevel = logLevel; + if (_client) { + _client = _client.withOptions({ logLevel }); + } + return {}; }); } /** * Selects the tools to include in the MCP Server based on the provided options. */ -export function selectTools(endpoints: Endpoint[], options: McpOptions) { - const filteredEndpoints = query(options.filters, endpoints); - - let includedTools = filteredEndpoints; - - 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; - } +export function selectTools(options?: McpOptions): McpTool[] { + const includedTools = []; + + if (options?.includeCodeTool ?? true) { + includedTools.push( + codeTool({ + blockedMethods: blockedMethodsForCodeTool(options), + codeExecutionMode: options?.codeExecutionMode ?? 'stainless-sandbox', + }), + ); } - - const capabilities = { ...defaultClientCapabilities, ...options.capabilities }; - return applyCompatibilityTransformations(includedTools, capabilities); + if (options?.includeDocsTools ?? true) { + includedTools.push(docsSearchTool); + } + return includedTools; } /** * Runs the provided handler with the given client and arguments. */ -export async function executeHandler( - tool: Tool, - handler: HandlerFunction, - client: Beagle, - args: Record | undefined, - compatibilityOptions?: Partial, -) { - const options = { ...defaultClientCapabilities, ...compatibilityOptions }; - if (options.validJson && args) { - args = parseEmbeddedJSON(args, tool.inputSchema); - } - return await handler(client, args || {}); +export async function executeHandler({ + handler, + reqContext, + args, +}: { + handler: HandlerFunction; + reqContext: McpRequestContext; + args: Record | undefined; +}): Promise { + return await handler({ reqContext, args: args || {} }); } - -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/stdio.ts b/packages/mcp-server/src/stdio.ts new file mode 100644 index 00000000..b04a5441 --- /dev/null +++ b/packages/mcp-server/src/stdio.ts @@ -0,0 +1,17 @@ +import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; +import { McpOptions } from './options'; +import { initMcpServer, newMcpServer } from './server'; +import { getLogger } from './logger'; + +export const launchStdioServer = async (mcpOptions: McpOptions) => { + const server = await newMcpServer({ + stainlessApiKey: mcpOptions.stainlessApiKey, + customInstructionsPath: mcpOptions.customInstructionsPath, + }); + + await initMcpServer({ server, mcpOptions, stainlessApiKey: mcpOptions.stainlessApiKey }); + + const transport = new StdioServerTransport(); + await server.connect(transport); + getLogger().info('MCP Server running on stdio'); +}; diff --git a/packages/mcp-server/src/tools.ts b/packages/mcp-server/src/tools.ts deleted file mode 100644 index 7e516de7..00000000 --- a/packages/mcp-server/src/tools.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './tools/index'; diff --git a/packages/mcp-server/src/tools/enrollments/create-enrollments.ts b/packages/mcp-server/src/tools/enrollments/create-enrollments.ts deleted file mode 100644 index da244936..00000000 --- a/packages/mcp-server/src/tools/enrollments/create-enrollments.ts +++ /dev/null @@ -1,51 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -import { asTextContentResult } from 'beagle-mcp/tools/types'; - -import { Tool } from '@modelcontextprotocol/sdk/types.js'; -import type { Metadata } from '../'; -import Beagle from 'beagle'; - -export const metadata: Metadata = { - resource: 'enrollments', - operation: 'write', - tags: [], - httpMethod: 'post', - httpPath: '/api/enrollments', - operationId: 'createEnrollment', -}; - -export const tool: Tool = { - name: 'create_enrollments', - description: 'create a new enrollment for a tenant.', - inputSchema: { - type: 'object', - properties: { - effectiveDate: { - type: 'string', - description: 'the date the enrollment will begin, note enrollments cannot begin in the past', - }, - plan: { - type: 'string', - description: 'the plan name/code', - }, - propertyManagerId: { - type: 'number', - }, - tenantId: { - type: 'number', - }, - note: { - type: 'string', - description: 'an optional note field, this can be used for easily appending metadata to enrollments', - }, - }, - }, -}; - -export const handler = async (client: Beagle, args: Record | undefined) => { - const body = args as any; - return asTextContentResult(await client.enrollments.create(body)); -}; - -export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/enrollments/lapse-enrollments.ts b/packages/mcp-server/src/tools/enrollments/lapse-enrollments.ts deleted file mode 100644 index d9448fd1..00000000 --- a/packages/mcp-server/src/tools/enrollments/lapse-enrollments.ts +++ /dev/null @@ -1,38 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -import { asTextContentResult } from 'beagle-mcp/tools/types'; - -import { Tool } from '@modelcontextprotocol/sdk/types.js'; -import type { Metadata } from '../'; -import Beagle from 'beagle'; - -export const metadata: Metadata = { - resource: 'enrollments', - operation: 'write', - tags: [], - httpMethod: 'delete', - httpPath: '/api/enrollments/{id}', - operationId: 'lapseEnrollment', -}; - -export const tool: Tool = { - name: 'lapse_enrollments', - description: - 'lapses a specific enrollment for a tenant, note that if a tenant has multiple enrollments (e.g., SDR and TLL), each must be lapsed individually', - inputSchema: { - type: 'object', - properties: { - id: { - type: 'number', - }, - }, - }, -}; - -export const handler = async (client: Beagle, args: Record | undefined) => { - const { id, ...body } = args as any; - const response = await client.enrollments.lapse(id).asResponse(); - return asTextContentResult(await response.text()); -}; - -export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/enrollments/list-enrollments.ts b/packages/mcp-server/src/tools/enrollments/list-enrollments.ts deleted file mode 100644 index dbbaf68e..00000000 --- a/packages/mcp-server/src/tools/enrollments/list-enrollments.ts +++ /dev/null @@ -1,45 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -import { asTextContentResult } from 'beagle-mcp/tools/types'; - -import { Tool } from '@modelcontextprotocol/sdk/types.js'; -import type { Metadata } from '../'; -import Beagle from 'beagle'; - -export const metadata: Metadata = { - resource: 'enrollments', - operation: 'read', - tags: [], - httpMethod: 'get', - httpPath: '/api/enrollments', - operationId: 'listEnrollments', -}; - -export const tool: Tool = { - name: 'list_enrollments', - description: - 'list all enrollments, this endpoint is paginated and allows for queries by individual property manager.', - inputSchema: { - type: 'object', - properties: { - page: { - type: 'number', - description: 'Page number to fetch.', - }, - propertyManagerId: { - type: 'number', - }, - size: { - type: 'number', - description: 'Number of items per page.', - }, - }, - }, -}; - -export const handler = async (client: Beagle, args: Record | undefined) => { - const body = args as any; - return asTextContentResult(await client.enrollments.list(body)); -}; - -export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/enrollments/retrieve-enrollments.ts b/packages/mcp-server/src/tools/enrollments/retrieve-enrollments.ts deleted file mode 100644 index a8c7de7d..00000000 --- a/packages/mcp-server/src/tools/enrollments/retrieve-enrollments.ts +++ /dev/null @@ -1,36 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -import { asTextContentResult } from 'beagle-mcp/tools/types'; - -import { Tool } from '@modelcontextprotocol/sdk/types.js'; -import type { Metadata } from '../'; -import Beagle from 'beagle'; - -export const metadata: Metadata = { - resource: 'enrollments', - operation: 'read', - tags: [], - httpMethod: 'get', - httpPath: '/api/enrollments/{id}', - operationId: 'getEnrollment', -}; - -export const tool: Tool = { - name: 'retrieve_enrollments', - description: 'get a specific enrollment by its id.', - inputSchema: { - type: 'object', - properties: { - id: { - type: 'number', - }, - }, - }, -}; - -export const handler = async (client: Beagle, args: Record | undefined) => { - const { id, ...body } = args as any; - return asTextContentResult(await client.enrollments.retrieve(id)); -}; - -export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/index.ts b/packages/mcp-server/src/tools/index.ts deleted file mode 100644 index 39ab480c..00000000 --- a/packages/mcp-server/src/tools/index.ts +++ /dev/null @@ -1,113 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -import { Metadata, Endpoint, HandlerFunction } from './types'; - -export { Metadata, Endpoint, HandlerFunction }; - -import retrieve_plans from './plans/retrieve-plans'; -import list_plans from './plans/list-plans'; -import create_property_managers from './property-managers/create-property-managers'; -import retrieve_property_managers from './property-managers/retrieve-property-managers'; -import update_property_managers from './property-managers/update-property-managers'; -import list_property_managers from './property-managers/list-property-managers'; -import delete_property_managers from './property-managers/delete-property-managers'; -import create_tenants from './tenants/create-tenants'; -import retrieve_tenants from './tenants/retrieve-tenants'; -import update_tenants from './tenants/update-tenants'; -import list_tenants from './tenants/list-tenants'; -import delete_tenants from './tenants/delete-tenants'; -import create_enrollments from './enrollments/create-enrollments'; -import retrieve_enrollments from './enrollments/retrieve-enrollments'; -import list_enrollments from './enrollments/list-enrollments'; -import lapse_enrollments from './enrollments/lapse-enrollments'; -import verify_insurance_verification from './insurance-verification/verify-insurance-verification'; -import create_webhook_endpoints from './webhook/endpoints/create-webhook-endpoints'; -import retrieve_webhook_endpoints from './webhook/endpoints/retrieve-webhook-endpoints'; -import update_webhook_endpoints from './webhook/endpoints/update-webhook-endpoints'; -import list_webhook_endpoints from './webhook/endpoints/list-webhook-endpoints'; -import delete_webhook_endpoints from './webhook/endpoints/delete-webhook-endpoints'; - -export const endpoints: Endpoint[] = []; - -function addEndpoint(endpoint: Endpoint) { - endpoints.push(endpoint); -} - -addEndpoint(retrieve_plans); -addEndpoint(list_plans); -addEndpoint(create_property_managers); -addEndpoint(retrieve_property_managers); -addEndpoint(update_property_managers); -addEndpoint(list_property_managers); -addEndpoint(delete_property_managers); -addEndpoint(create_tenants); -addEndpoint(retrieve_tenants); -addEndpoint(update_tenants); -addEndpoint(list_tenants); -addEndpoint(delete_tenants); -addEndpoint(create_enrollments); -addEndpoint(retrieve_enrollments); -addEndpoint(list_enrollments); -addEndpoint(lapse_enrollments); -addEndpoint(verify_insurance_verification); -addEndpoint(create_webhook_endpoints); -addEndpoint(retrieve_webhook_endpoints); -addEndpoint(update_webhook_endpoints); -addEndpoint(list_webhook_endpoints); -addEndpoint(delete_webhook_endpoints); - -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 - 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: ${unmatched - .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/insurance-verification/verify-insurance-verification.ts b/packages/mcp-server/src/tools/insurance-verification/verify-insurance-verification.ts deleted file mode 100644 index bd2b0de8..00000000 --- a/packages/mcp-server/src/tools/insurance-verification/verify-insurance-verification.ts +++ /dev/null @@ -1,46 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -import { asTextContentResult } from 'beagle-mcp/tools/types'; - -import { Tool } from '@modelcontextprotocol/sdk/types.js'; -import type { Metadata } from '../'; -import Beagle from 'beagle'; - -export const metadata: Metadata = { - resource: 'insurance_verification', - operation: 'write', - tags: [], - httpMethod: 'post', - httpPath: '/api/insurance-verification', - operationId: 'verifyInsurance', -}; - -export const tool: Tool = { - name: 'verify_insurance_verification', - description: 'trigger a job to parse a tenants insurance document(s)', - inputSchema: { - type: 'object', - properties: { - propertyManagerId: { - type: 'number', - }, - tenantId: { - type: 'number', - }, - urls: { - type: 'array', - description: 'an array of presigned pdf urls for the tenants policy document(s)', - items: { - type: 'string', - }, - }, - }, - }, -}; - -export const handler = async (client: Beagle, args: Record | undefined) => { - const body = args as any; - return asTextContentResult(await client.insuranceVerification.verify(body)); -}; - -export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/plans/list-plans.ts b/packages/mcp-server/src/tools/plans/list-plans.ts deleted file mode 100644 index 81eef257..00000000 --- a/packages/mcp-server/src/tools/plans/list-plans.ts +++ /dev/null @@ -1,32 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -import { asTextContentResult } from 'beagle-mcp/tools/types'; - -import { Tool } from '@modelcontextprotocol/sdk/types.js'; -import type { Metadata } from '../'; -import Beagle from 'beagle'; - -export const metadata: Metadata = { - resource: 'plans', - operation: 'read', - tags: [], - httpMethod: 'get', - httpPath: '/api/plans', - operationId: 'listPlans', -}; - -export const tool: Tool = { - name: 'list_plans', - description: - 'list all available plans, note this endpoint is currently unpaginated unlike all other list endpoints.', - inputSchema: { - type: 'object', - properties: {}, - }, -}; - -export const handler = async (client: Beagle, args: Record | undefined) => { - return asTextContentResult(await client.plans.list()); -}; - -export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/plans/retrieve-plans.ts b/packages/mcp-server/src/tools/plans/retrieve-plans.ts deleted file mode 100644 index dfdd90c3..00000000 --- a/packages/mcp-server/src/tools/plans/retrieve-plans.ts +++ /dev/null @@ -1,36 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -import { asTextContentResult } from 'beagle-mcp/tools/types'; - -import { Tool } from '@modelcontextprotocol/sdk/types.js'; -import type { Metadata } from '../'; -import Beagle from 'beagle'; - -export const metadata: Metadata = { - resource: 'plans', - operation: 'read', - tags: [], - httpMethod: 'get', - httpPath: '/api/plans/{code}', - operationId: 'getPlan', -}; - -export const tool: Tool = { - name: 'retrieve_plans', - description: 'retrieve a specific plans details by its code.', - inputSchema: { - type: 'object', - properties: { - code: { - type: 'string', - }, - }, - }, -}; - -export const handler = async (client: Beagle, args: Record | undefined) => { - const { code, ...body } = args as any; - return asTextContentResult(await client.plans.retrieve(code)); -}; - -export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/property-managers/create-property-managers.ts b/packages/mcp-server/src/tools/property-managers/create-property-managers.ts deleted file mode 100644 index 6859dbb8..00000000 --- a/packages/mcp-server/src/tools/property-managers/create-property-managers.ts +++ /dev/null @@ -1,106 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -import { asTextContentResult } from 'beagle-mcp/tools/types'; - -import { Tool } from '@modelcontextprotocol/sdk/types.js'; -import type { Metadata } from '../'; -import Beagle from 'beagle'; - -export const metadata: Metadata = { - resource: 'property_managers', - operation: 'write', - tags: [], - httpMethod: 'post', - httpPath: '/api/property-managers', - operationId: 'createPropertyManager', -}; - -export const tool: Tool = { - name: 'create_property_managers', - description: 'create a new property manager.', - inputSchema: { - type: 'object', - properties: { - addresses: { - type: 'array', - items: { - allOf: [ - { - $ref: '#/$defs/address', - }, - ], - }, - }, - contacts: { - type: 'array', - items: { - allOf: [ - { - $ref: '#/$defs/contact', - }, - ], - }, - }, - name: { - type: 'string', - description: 'name of the property manager', - }, - }, - $defs: { - address: { - type: 'object', - properties: { - city: { - type: 'string', - }, - state: { - type: 'string', - description: 'two letter state code, ie CA', - }, - street1: { - type: 'string', - }, - zip: { - type: 'string', - description: '5 digit US zip code, ie 94104', - }, - street2: { - type: 'string', - }, - }, - required: ['city', 'state', 'street1', 'zip'], - }, - contact: { - type: 'object', - properties: { - email: { - type: 'string', - }, - name: { - type: 'object', - properties: { - first: { - type: 'string', - }, - last: { - type: 'string', - }, - }, - required: ['first', 'last'], - }, - phone: { - type: 'string', - }, - }, - required: ['email', 'name'], - }, - }, - }, -}; - -export const handler = async (client: Beagle, args: Record | undefined) => { - const body = args as any; - return asTextContentResult(await client.propertyManagers.create(body)); -}; - -export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/property-managers/delete-property-managers.ts b/packages/mcp-server/src/tools/property-managers/delete-property-managers.ts deleted file mode 100644 index f0cc53af..00000000 --- a/packages/mcp-server/src/tools/property-managers/delete-property-managers.ts +++ /dev/null @@ -1,37 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -import { asTextContentResult } from 'beagle-mcp/tools/types'; - -import { Tool } from '@modelcontextprotocol/sdk/types.js'; -import type { Metadata } from '../'; -import Beagle from 'beagle'; - -export const metadata: Metadata = { - resource: 'property_managers', - operation: 'write', - tags: [], - httpMethod: 'delete', - httpPath: '/api/property-managers/{id}', - operationId: 'deletePropertyManager', -}; - -export const tool: Tool = { - name: 'delete_property_managers', - description: 'delete a property manager by id.', - inputSchema: { - type: 'object', - properties: { - id: { - type: 'number', - }, - }, - }, -}; - -export const handler = async (client: Beagle, args: Record | undefined) => { - const { id, ...body } = args as any; - const response = await client.propertyManagers.delete(id).asResponse(); - return asTextContentResult(await response.text()); -}; - -export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/property-managers/list-property-managers.ts b/packages/mcp-server/src/tools/property-managers/list-property-managers.ts deleted file mode 100644 index 7e8f8a93..00000000 --- a/packages/mcp-server/src/tools/property-managers/list-property-managers.ts +++ /dev/null @@ -1,41 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -import { asTextContentResult } from 'beagle-mcp/tools/types'; - -import { Tool } from '@modelcontextprotocol/sdk/types.js'; -import type { Metadata } from '../'; -import Beagle from 'beagle'; - -export const metadata: Metadata = { - resource: 'property_managers', - operation: 'read', - tags: [], - httpMethod: 'get', - httpPath: '/api/property-managers', - operationId: 'listPropertyManagers', -}; - -export const tool: Tool = { - name: 'list_property_managers', - description: 'list all property managers, note this endpoint is paginated.', - inputSchema: { - type: 'object', - properties: { - page: { - type: 'number', - description: 'Page number to fetch.', - }, - size: { - type: 'number', - description: 'Number of items per page.', - }, - }, - }, -}; - -export const handler = async (client: Beagle, args: Record | undefined) => { - const body = args as any; - return asTextContentResult(await client.propertyManagers.list(body)); -}; - -export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/property-managers/retrieve-property-managers.ts b/packages/mcp-server/src/tools/property-managers/retrieve-property-managers.ts deleted file mode 100644 index 9f92d67f..00000000 --- a/packages/mcp-server/src/tools/property-managers/retrieve-property-managers.ts +++ /dev/null @@ -1,36 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -import { asTextContentResult } from 'beagle-mcp/tools/types'; - -import { Tool } from '@modelcontextprotocol/sdk/types.js'; -import type { Metadata } from '../'; -import Beagle from 'beagle'; - -export const metadata: Metadata = { - resource: 'property_managers', - operation: 'read', - tags: [], - httpMethod: 'get', - httpPath: '/api/property-managers/{id}', - operationId: 'getPropertyManager', -}; - -export const tool: Tool = { - name: 'retrieve_property_managers', - description: 'get a property manager by id.', - inputSchema: { - type: 'object', - properties: { - id: { - type: 'number', - }, - }, - }, -}; - -export const handler = async (client: Beagle, args: Record | undefined) => { - const { id, ...body } = args as any; - return asTextContentResult(await client.propertyManagers.retrieve(id)); -}; - -export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/property-managers/update-property-managers.ts b/packages/mcp-server/src/tools/property-managers/update-property-managers.ts deleted file mode 100644 index a84df734..00000000 --- a/packages/mcp-server/src/tools/property-managers/update-property-managers.ts +++ /dev/null @@ -1,110 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -import { asTextContentResult } from 'beagle-mcp/tools/types'; - -import { Tool } from '@modelcontextprotocol/sdk/types.js'; -import type { Metadata } from '../'; -import Beagle from 'beagle'; - -export const metadata: Metadata = { - resource: 'property_managers', - operation: 'write', - tags: [], - httpMethod: 'patch', - httpPath: '/api/property-managers/{id}', - operationId: 'updatePropertyManager', -}; - -export const tool: Tool = { - name: 'update_property_managers', - description: - 'update an existing property manager by id, note that when updating contacts or addresses you need to send the whole array you want to replace them with.', - inputSchema: { - type: 'object', - properties: { - id: { - type: 'number', - }, - addresses: { - type: 'array', - items: { - allOf: [ - { - $ref: '#/$defs/address', - }, - ], - }, - }, - contacts: { - type: 'array', - items: { - allOf: [ - { - $ref: '#/$defs/contact', - }, - ], - }, - }, - name: { - type: 'string', - description: 'name of the property manager', - }, - }, - $defs: { - address: { - type: 'object', - properties: { - city: { - type: 'string', - }, - state: { - type: 'string', - description: 'two letter state code, ie CA', - }, - street1: { - type: 'string', - }, - zip: { - type: 'string', - description: '5 digit US zip code, ie 94104', - }, - street2: { - type: 'string', - }, - }, - required: ['city', 'state', 'street1', 'zip'], - }, - contact: { - type: 'object', - properties: { - email: { - type: 'string', - }, - name: { - type: 'object', - properties: { - first: { - type: 'string', - }, - last: { - type: 'string', - }, - }, - required: ['first', 'last'], - }, - phone: { - type: 'string', - }, - }, - required: ['email', 'name'], - }, - }, - }, -}; - -export const handler = async (client: Beagle, args: Record | undefined) => { - const { id, ...body } = args as any; - return asTextContentResult(await client.propertyManagers.update(id, body)); -}; - -export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/tenants/create-tenants.ts b/packages/mcp-server/src/tools/tenants/create-tenants.ts deleted file mode 100644 index 468ce5d9..00000000 --- a/packages/mcp-server/src/tools/tenants/create-tenants.ts +++ /dev/null @@ -1,91 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -import { asTextContentResult } from 'beagle-mcp/tools/types'; - -import { Tool } from '@modelcontextprotocol/sdk/types.js'; -import type { Metadata } from '../'; -import Beagle from 'beagle'; - -export const metadata: Metadata = { - resource: 'tenants', - operation: 'write', - tags: [], - httpMethod: 'post', - httpPath: '/api/tenants', - operationId: 'createTenant', -}; - -export const tool: Tool = { - name: 'create_tenants', - description: 'create a new tenant.', - inputSchema: { - type: 'object', - properties: { - address: { - $ref: '#/$defs/address', - }, - contact: { - $ref: '#/$defs/contact', - }, - propertyManagerId: { - type: 'number', - }, - }, - $defs: { - address: { - type: 'object', - properties: { - city: { - type: 'string', - }, - state: { - type: 'string', - description: 'two letter state code, ie CA', - }, - street1: { - type: 'string', - }, - zip: { - type: 'string', - description: '5 digit US zip code, ie 94104', - }, - street2: { - type: 'string', - }, - }, - required: ['city', 'state', 'street1', 'zip'], - }, - contact: { - type: 'object', - properties: { - email: { - type: 'string', - }, - name: { - type: 'object', - properties: { - first: { - type: 'string', - }, - last: { - type: 'string', - }, - }, - required: ['first', 'last'], - }, - phone: { - type: 'string', - }, - }, - required: ['email', 'name'], - }, - }, - }, -}; - -export const handler = async (client: Beagle, args: Record | undefined) => { - const body = args as any; - return asTextContentResult(await client.tenants.create(body)); -}; - -export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/tenants/delete-tenants.ts b/packages/mcp-server/src/tools/tenants/delete-tenants.ts deleted file mode 100644 index ce21e419..00000000 --- a/packages/mcp-server/src/tools/tenants/delete-tenants.ts +++ /dev/null @@ -1,37 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -import { asTextContentResult } from 'beagle-mcp/tools/types'; - -import { Tool } from '@modelcontextprotocol/sdk/types.js'; -import type { Metadata } from '../'; -import Beagle from 'beagle'; - -export const metadata: Metadata = { - resource: 'tenants', - operation: 'write', - tags: [], - httpMethod: 'delete', - httpPath: '/api/tenants/{id}', - operationId: 'deleteTenant', -}; - -export const tool: Tool = { - name: 'delete_tenants', - description: 'delete an existing tenant by their id.', - inputSchema: { - type: 'object', - properties: { - id: { - type: 'number', - }, - }, - }, -}; - -export const handler = async (client: Beagle, args: Record | undefined) => { - const { id, ...body } = args as any; - const response = await client.tenants.delete(id).asResponse(); - return asTextContentResult(await response.text()); -}; - -export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/tenants/list-tenants.ts b/packages/mcp-server/src/tools/tenants/list-tenants.ts deleted file mode 100644 index daf97ca6..00000000 --- a/packages/mcp-server/src/tools/tenants/list-tenants.ts +++ /dev/null @@ -1,45 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -import { asTextContentResult } from 'beagle-mcp/tools/types'; - -import { Tool } from '@modelcontextprotocol/sdk/types.js'; -import type { Metadata } from '../'; -import Beagle from 'beagle'; - -export const metadata: Metadata = { - resource: 'tenants', - operation: 'read', - tags: [], - httpMethod: 'get', - httpPath: '/api/tenants', - operationId: 'listTenants', -}; - -export const tool: Tool = { - name: 'list_tenants', - description: - 'list all tenants, this endpoint is paginated and allows for queries by individual property manager.', - inputSchema: { - type: 'object', - properties: { - page: { - type: 'number', - description: 'Page number to fetch.', - }, - propertyManagerId: { - type: 'number', - }, - size: { - type: 'number', - description: 'Number of items per page.', - }, - }, - }, -}; - -export const handler = async (client: Beagle, args: Record | undefined) => { - const body = args as any; - return asTextContentResult(await client.tenants.list(body)); -}; - -export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/tenants/retrieve-tenants.ts b/packages/mcp-server/src/tools/tenants/retrieve-tenants.ts deleted file mode 100644 index d01cd975..00000000 --- a/packages/mcp-server/src/tools/tenants/retrieve-tenants.ts +++ /dev/null @@ -1,36 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -import { asTextContentResult } from 'beagle-mcp/tools/types'; - -import { Tool } from '@modelcontextprotocol/sdk/types.js'; -import type { Metadata } from '../'; -import Beagle from 'beagle'; - -export const metadata: Metadata = { - resource: 'tenants', - operation: 'read', - tags: [], - httpMethod: 'get', - httpPath: '/api/tenants/{id}', - operationId: 'getTenant', -}; - -export const tool: Tool = { - name: 'retrieve_tenants', - description: 'retrieve a single tenant by their id.', - inputSchema: { - type: 'object', - properties: { - id: { - type: 'number', - }, - }, - }, -}; - -export const handler = async (client: Beagle, args: Record | undefined) => { - const { id, ...body } = args as any; - return asTextContentResult(await client.tenants.retrieve(id)); -}; - -export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/tenants/update-tenants.ts b/packages/mcp-server/src/tools/tenants/update-tenants.ts deleted file mode 100644 index d73c472d..00000000 --- a/packages/mcp-server/src/tools/tenants/update-tenants.ts +++ /dev/null @@ -1,91 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -import { asTextContentResult } from 'beagle-mcp/tools/types'; - -import { Tool } from '@modelcontextprotocol/sdk/types.js'; -import type { Metadata } from '../'; -import Beagle from 'beagle'; - -export const metadata: Metadata = { - resource: 'tenants', - operation: 'write', - tags: [], - httpMethod: 'patch', - httpPath: '/api/tenants/{id}', - operationId: 'updateTenant', -}; - -export const tool: Tool = { - name: 'update_tenants', - description: 'update an existing tenant by their id.', - inputSchema: { - type: 'object', - properties: { - id: { - type: 'number', - }, - address: { - $ref: '#/$defs/address', - }, - contact: { - $ref: '#/$defs/contact', - }, - }, - $defs: { - address: { - type: 'object', - properties: { - city: { - type: 'string', - }, - state: { - type: 'string', - description: 'two letter state code, ie CA', - }, - street1: { - type: 'string', - }, - zip: { - type: 'string', - description: '5 digit US zip code, ie 94104', - }, - street2: { - type: 'string', - }, - }, - required: ['city', 'state', 'street1', 'zip'], - }, - contact: { - type: 'object', - properties: { - email: { - type: 'string', - }, - name: { - type: 'object', - properties: { - first: { - type: 'string', - }, - last: { - type: 'string', - }, - }, - required: ['first', 'last'], - }, - phone: { - type: 'string', - }, - }, - required: ['email', 'name'], - }, - }, - }, -}; - -export const handler = async (client: Beagle, args: Record | undefined) => { - const { id, ...body } = args as any; - return asTextContentResult(await client.tenants.update(id, body)); -}; - -export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/webhook/endpoints/create-webhook-endpoints.ts b/packages/mcp-server/src/tools/webhook/endpoints/create-webhook-endpoints.ts deleted file mode 100644 index baded88d..00000000 --- a/packages/mcp-server/src/tools/webhook/endpoints/create-webhook-endpoints.ts +++ /dev/null @@ -1,42 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -import { asTextContentResult } from 'beagle-mcp/tools/types'; - -import { Tool } from '@modelcontextprotocol/sdk/types.js'; -import type { Metadata } from '../../'; -import Beagle from 'beagle'; - -export const metadata: Metadata = { - resource: 'webhook.endpoints', - operation: 'write', - tags: [], - httpMethod: 'post', - httpPath: '/api/webhook/endpoints', - operationId: 'createWebhookEndpoint', -}; - -export const tool: Tool = { - name: 'create_webhook_endpoints', - description: 'creates a new webhook target.', - inputSchema: { - type: 'object', - properties: { - secret: { - type: 'string', - }, - url: { - type: 'string', - }, - active: { - type: 'boolean', - }, - }, - }, -}; - -export const handler = async (client: Beagle, args: Record | undefined) => { - const body = args as any; - return asTextContentResult(await client.webhook.endpoints.create(body)); -}; - -export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/webhook/endpoints/delete-webhook-endpoints.ts b/packages/mcp-server/src/tools/webhook/endpoints/delete-webhook-endpoints.ts deleted file mode 100644 index 8dd99609..00000000 --- a/packages/mcp-server/src/tools/webhook/endpoints/delete-webhook-endpoints.ts +++ /dev/null @@ -1,37 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -import { asTextContentResult } from 'beagle-mcp/tools/types'; - -import { Tool } from '@modelcontextprotocol/sdk/types.js'; -import type { Metadata } from '../../'; -import Beagle from 'beagle'; - -export const metadata: Metadata = { - resource: 'webhook.endpoints', - operation: 'write', - tags: [], - httpMethod: 'delete', - httpPath: '/api/webhook/endpoints/{id}', - operationId: 'deleteWebhookEndpoint', -}; - -export const tool: Tool = { - name: 'delete_webhook_endpoints', - description: 'delete an existing webhook endpoint by its id.', - inputSchema: { - type: 'object', - properties: { - id: { - type: 'number', - }, - }, - }, -}; - -export const handler = async (client: Beagle, args: Record | undefined) => { - const { id, ...body } = args as any; - const response = await client.webhook.endpoints.delete(id).asResponse(); - return asTextContentResult(await response.text()); -}; - -export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/webhook/endpoints/list-webhook-endpoints.ts b/packages/mcp-server/src/tools/webhook/endpoints/list-webhook-endpoints.ts deleted file mode 100644 index 6f623693..00000000 --- a/packages/mcp-server/src/tools/webhook/endpoints/list-webhook-endpoints.ts +++ /dev/null @@ -1,42 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -import { asTextContentResult } from 'beagle-mcp/tools/types'; - -import { Tool } from '@modelcontextprotocol/sdk/types.js'; -import type { Metadata } from '../../'; -import Beagle from 'beagle'; - -export const metadata: Metadata = { - resource: 'webhook.endpoints', - operation: 'read', - tags: [], - httpMethod: 'get', - httpPath: '/api/webhook/endpoints', - operationId: 'listWebhookEndpoints', -}; - -export const tool: Tool = { - name: 'list_webhook_endpoints', - description: - 'list all webhook endpoints, this endpoint is paginated and allows for queries by individual property manager.', - inputSchema: { - type: 'object', - properties: { - page: { - type: 'number', - description: 'Page number to fetch.', - }, - size: { - type: 'number', - description: 'Number of items per page.', - }, - }, - }, -}; - -export const handler = async (client: Beagle, args: Record | undefined) => { - const body = args as any; - return asTextContentResult(await client.webhook.endpoints.list(body)); -}; - -export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/webhook/endpoints/retrieve-webhook-endpoints.ts b/packages/mcp-server/src/tools/webhook/endpoints/retrieve-webhook-endpoints.ts deleted file mode 100644 index bddb2361..00000000 --- a/packages/mcp-server/src/tools/webhook/endpoints/retrieve-webhook-endpoints.ts +++ /dev/null @@ -1,36 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -import { asTextContentResult } from 'beagle-mcp/tools/types'; - -import { Tool } from '@modelcontextprotocol/sdk/types.js'; -import type { Metadata } from '../../'; -import Beagle from 'beagle'; - -export const metadata: Metadata = { - resource: 'webhook.endpoints', - operation: 'read', - tags: [], - httpMethod: 'get', - httpPath: '/api/webhook/endpoints/{id}', - operationId: 'getWebhookEndpoint', -}; - -export const tool: Tool = { - name: 'retrieve_webhook_endpoints', - description: 'retrieve a single webhook endpoint by its id.', - inputSchema: { - type: 'object', - properties: { - id: { - type: 'number', - }, - }, - }, -}; - -export const handler = async (client: Beagle, args: Record | undefined) => { - const { id, ...body } = args as any; - return asTextContentResult(await client.webhook.endpoints.retrieve(id)); -}; - -export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/webhook/endpoints/update-webhook-endpoints.ts b/packages/mcp-server/src/tools/webhook/endpoints/update-webhook-endpoints.ts deleted file mode 100644 index 01232d18..00000000 --- a/packages/mcp-server/src/tools/webhook/endpoints/update-webhook-endpoints.ts +++ /dev/null @@ -1,45 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -import { asTextContentResult } from 'beagle-mcp/tools/types'; - -import { Tool } from '@modelcontextprotocol/sdk/types.js'; -import type { Metadata } from '../../'; -import Beagle from 'beagle'; - -export const metadata: Metadata = { - resource: 'webhook.endpoints', - operation: 'write', - tags: [], - httpMethod: 'patch', - httpPath: '/api/webhook/endpoints/{id}', - operationId: 'updateWebhookEndpoint', -}; - -export const tool: Tool = { - name: 'update_webhook_endpoints', - description: 'update an existing webhook endpoint by its id.', - inputSchema: { - type: 'object', - properties: { - id: { - type: 'number', - }, - secret: { - type: 'string', - }, - url: { - type: 'string', - }, - active: { - type: 'boolean', - }, - }, - }, -}; - -export const handler = async (client: Beagle, args: Record | undefined) => { - const { id, ...body } = args as any; - return asTextContentResult(await client.webhook.endpoints.update(id, body)); -}; - -export default { metadata, tool, handler }; diff --git a/packages/mcp-server/src/tools/types.ts b/packages/mcp-server/src/types.ts similarity index 72% rename from packages/mcp-server/src/tools/types.ts rename to packages/mcp-server/src/types.ts index 009c4212..28a7f5c2 100644 --- a/packages/mcp-server/src/tools/types.ts +++ b/packages/mcp-server/src/types.ts @@ -1,6 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import Beagle from 'beagle'; +import Beagle from '@corgi-tech/beagle'; import { Tool } from '@modelcontextprotocol/sdk/types.js'; type TextContentBlock = { @@ -42,12 +42,23 @@ export type ToolCallResult = { isError?: boolean; }; -export type HandlerFunction = ( - client: Beagle, - args: Record | undefined, -) => Promise; +export type McpRequestContext = { + client: Beagle; + stainlessApiKey?: string | undefined; + upstreamClientEnvs?: Record | undefined; + mcpSessionId?: string | undefined; + mcpClientInfo?: { name: string; version: string } | undefined; +}; + +export type HandlerFunction = ({ + reqContext, + args, +}: { + reqContext: McpRequestContext; + args: Record | undefined; +}) => Promise; -export function asTextContentResult(result: Object): ToolCallResult { +export function asTextContentResult(result: unknown): ToolCallResult { return { content: [ { @@ -87,6 +98,18 @@ export async function asBinaryContentResult(response: Response): Promise { + if (typeof (globalThis as any).process !== 'undefined') { + return (globalThis as any).process.env?.[env]?.trim() || undefined; + } else if (typeof (globalThis as any).Deno !== 'undefined') { + return (globalThis as any).Deno.env?.get?.(env)?.trim() || undefined; + } + 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; +}; + +export const requireValue = (value: T | undefined, description: string): T => { + if (value === undefined) { + throw new Error(`Missing required value: ${description}`); + } + return value; +}; diff --git a/packages/mcp-server/tests/compat.test.ts b/packages/mcp-server/tests/compat.test.ts deleted file mode 100644 index d6272f6c..00000000 --- a/packages/mcp-server/tests/compat.test.ts +++ /dev/null @@ -1,1166 +0,0 @@ -import { - truncateToolNames, - removeTopLevelUnions, - removeAnyOf, - inlineRefs, - applyCompatibilityTransformations, - removeFormats, - findUsedDefs, -} 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('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 = { - 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 deleted file mode 100644 index 08963af8..00000000 --- a/packages/mcp-server/tests/dynamic-tools.test.ts +++ /dev/null @@ -1,185 +0,0 @@ -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); - - 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 () => { - 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'); - 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 () => { - 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 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 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 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[] }) => { - expect( - tool.name.toLowerCase().includes('admin') || - tool.resource.toLowerCase().includes('admin') || - tool.tags.some((tag: string) => tag.toLowerCase().includes('admin')), - ).toBeTruthy(); - }); - }); - - it('should filter endpoints by description', async () => { - 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'); - expect(result.tools[0].description).toBe('Test endpoint for user_endpoint'); - }); - - it('should filter endpoints by partial description match', async () => { - 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'); - }); - }); - - describe('get_api_endpoint_schema', () => { - it('should return schema for existing endpoint', async () => { - 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); - }); - - it('should throw error for non-existent endpoint', async () => { - await expect( - 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 () => { - await expect(toolsMap.get_api_endpoint_schema.handler(fakeClient, undefined)).rejects.toThrow( - 'No endpoint provided', - ); - }); - }); - - describe('invoke_api_endpoint', () => { - it('should successfully invoke endpoint with valid arguments', async () => { - const mockHandler = endpoints[0]?.handler as jest.Mock; - mockHandler.mockClear(); - - await toolsMap.invoke_api_endpoint.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 () => { - await expect( - toolsMap.invoke_api_endpoint.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 () => { - await expect(toolsMap.invoke_api_endpoint.handler(fakeClient, undefined)).rejects.toThrow( - 'No endpoint provided', - ); - }); - - it('should throw error for invalid argument schema', async () => { - await expect( - 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( - 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 index f7661d68..17306295 100644 --- a/packages/mcp-server/tests/options.test.ts +++ b/packages/mcp-server/tests/options.test.ts @@ -1,5 +1,4 @@ -import { parseOptions } from '../src/options'; -import { Filter } from '../src/tools'; +import { parseCLIOptions } from '../src/options'; // Mock process.argv const mockArgv = (args: string[]) => { @@ -10,177 +9,24 @@ const mockArgv = (args: string[]) => { }; }; -describe('parseOptions', () => { - it('should parse basic filter options', () => { - const cleanup = mockArgv([ - '--tool=test-tool', - '--resource=test-resource', - '--operation=read', - '--tag=test-tag', - ]); +describe('parseCLIOptions', () => { + it('default parsing should be stdio', () => { + const cleanup = mockArgv([]); - const result = parseOptions(); + const result = parseCLIOptions(); - 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.client).toEqual('openai-agents'); - - 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, - }); + expect(result.transport).toBe('stdio'); 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(); + it('using http transport with a port', () => { + const cleanup = mockArgv(['--transport=http', '--port=2222']); - expect(() => parseOptions()).toThrow(); + const result = parseCLIOptions(); - console.error = originalError; + expect(result.transport).toBe('http'); + expect(result.port).toBe(2222); cleanup(); }); }); diff --git a/packages/mcp-server/tests/tools.test.ts b/packages/mcp-server/tests/tools.test.ts deleted file mode 100644 index cfff24a2..00000000 --- a/packages/mcp-server/tests/tools.test.ts +++ /dev/null @@ -1,225 +0,0 @@ -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/tsconfig.build.json b/packages/mcp-server/tsconfig.build.json index 85c4e8fa..544c7ddf 100644 --- a/packages/mcp-server/tsconfig.build.json +++ b/packages/mcp-server/tsconfig.build.json @@ -5,8 +5,8 @@ "compilerOptions": { "rootDir": "./dist/src", "paths": { - "beagle-mcp/*": ["dist/src/*"], - "beagle-mcp": ["dist/src/index.ts"] + "@corgi-tech/beagle-mcp/*": ["./dist/src/*"], + "@corgi-tech/beagle-mcp": ["./dist/src/index.ts"] }, "noEmit": false, "declaration": true, diff --git a/packages/mcp-server/tsconfig.json b/packages/mcp-server/tsconfig.json index ec3fb0a9..68bce321 100644 --- a/packages/mcp-server/tsconfig.json +++ b/packages/mcp-server/tsconfig.json @@ -2,15 +2,14 @@ "include": ["src", "tests", "examples"], "exclude": [], "compilerOptions": { - "target": "es2020", - "lib": ["es2020"], + "target": "es2022", + "lib": ["es2022"], "module": "commonjs", "moduleResolution": "node", "esModuleInterop": true, - "baseUrl": "./", "paths": { - "beagle-mcp/*": ["src/*"], - "beagle-mcp": ["src/index.ts"] + "@corgi-tech/beagle-mcp/*": ["./src/*"], + "@corgi-tech/beagle-mcp": ["./src/index.ts"] }, "noEmit": true, diff --git a/packages/mcp-server/yarn.lock b/packages/mcp-server/yarn.lock index 9970ec32..c6b17b02 100644 --- a/packages/mcp-server/yarn.lock +++ b/packages/mcp-server/yarn.lock @@ -2,122 +2,134 @@ # 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" +"@anthropic-ai/mcpb@^2.1.2": + version "2.1.2" + resolved "https://registry.yarnpkg.com/@anthropic-ai/mcpb/-/mcpb-2.1.2.tgz#cf02801929734b8810961f22e2eb72758c27d527" + integrity sha512-goRbBC8ySo7SWb7tRzr+tL6FxDc4JPTRCdgfD2omba7freofvjq5rom1lBnYHZHo6Mizs1jAHJeN53aZbDoy8A== + dependencies: + "@inquirer/prompts" "^6.0.1" + commander "^13.1.0" + fflate "^0.8.2" + galactus "^1.0.0" + ignore "^7.0.5" + node-forge "^1.3.2" + pretty-bytes "^5.6.0" + zod "^3.25.67" + zod-to-json-schema "^3.24.6" + +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.28.6.tgz#72499312ec58b1e2245ba4a4f550c132be4982f7" + integrity sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q== + dependencies: + "@babel/helper-validator-identifier" "^7.28.5" 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/compat-data@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.28.6.tgz#103f466803fa0f059e82ccac271475470570d74c" + integrity sha512-2lfu57JtzctfIrcGMz992hyLlByuzgIk58+hhGCxjKZ3rWI82NnVLjXcaTqkI2NvlcvOskZaiZ5kjUALo3Lpxg== "@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" + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.28.6.tgz#531bf883a1126e53501ba46eb3bb414047af507f" + integrity sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw== + dependencies: + "@babel/code-frame" "^7.28.6" + "@babel/generator" "^7.28.6" + "@babel/helper-compilation-targets" "^7.28.6" + "@babel/helper-module-transforms" "^7.28.6" + "@babel/helpers" "^7.28.6" + "@babel/parser" "^7.28.6" + "@babel/template" "^7.28.6" + "@babel/traverse" "^7.28.6" + "@babel/types" "^7.28.6" + "@jridgewell/remapping" "^2.3.5" 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== +"@babel/generator@^7.28.6", "@babel/generator@^7.7.2": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.28.6.tgz#48dcc65d98fcc8626a48f72b62e263d25fc3c3f1" + integrity sha512-lOoVRwADj8hjf7al89tvQ2a1lf53Z+7tiXMgpZJL3maQPDxh0DgLMN62B2MKUOFcoodBHLMbDM6WAbKgNy5Suw== dependencies: - "@babel/parser" "^7.27.1" - "@babel/types" "^7.27.1" - "@jridgewell/gen-mapping" "^0.3.5" - "@jridgewell/trace-mapping" "^0.3.25" + "@babel/parser" "^7.28.6" + "@babel/types" "^7.28.6" + "@jridgewell/gen-mapping" "^0.3.12" + "@jridgewell/trace-mapping" "^0.3.28" 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== +"@babel/helper-compilation-targets@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz#32c4a3f41f12ed1532179b108a4d746e105c2b25" + integrity sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA== dependencies: - "@babel/compat-data" "^7.27.2" + "@babel/compat-data" "^7.28.6" "@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== +"@babel/helper-globals@^7.28.0": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@babel/helper-globals/-/helper-globals-7.28.0.tgz#b9430df2aa4e17bc28665eadeae8aa1d985e6674" + integrity sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw== + +"@babel/helper-module-imports@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz#60632cbd6ffb70b22823187201116762a03e2d5c" + integrity sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw== dependencies: - "@babel/traverse" "^7.27.1" - "@babel/types" "^7.27.1" + "@babel/traverse" "^7.28.6" + "@babel/types" "^7.28.6" -"@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== +"@babel/helper-module-transforms@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz#9312d9d9e56edc35aeb6e95c25d4106b50b9eb1e" + integrity sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA== dependencies: - "@babel/helper-module-imports" "^7.27.1" - "@babel/helper-validator-identifier" "^7.27.1" - "@babel/traverse" "^7.27.1" + "@babel/helper-module-imports" "^7.28.6" + "@babel/helper-validator-identifier" "^7.28.5" + "@babel/traverse" "^7.28.6" -"@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-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.28.6", "@babel/helper-plugin-utils@^7.8.0": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz#6f13ea251b68c8532e985fd532f28741a8af9ac8" + integrity sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug== "@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-identifier@^7.28.5": + version "7.28.5" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz#010b6938fab7cb7df74aa2bbc06aa503b8fe5fb4" + integrity sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q== "@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== +"@babel/helpers@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.28.6.tgz#fca903a313ae675617936e8998b814c415cbf5d7" + integrity sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw== dependencies: - "@babel/template" "^7.27.1" - "@babel/types" "^7.27.1" + "@babel/template" "^7.28.6" + "@babel/types" "^7.28.6" -"@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== +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.23.9", "@babel/parser@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.28.6.tgz#f01a8885b7fa1e56dd8a155130226cd698ef13fd" + integrity sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ== dependencies: - "@babel/types" "^7.27.1" + "@babel/types" "^7.28.6" "@babel/plugin-syntax-async-generators@^7.8.4": version "7.8.4" @@ -148,11 +160,11 @@ "@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== + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.28.6.tgz#b71d5914665f60124e133696f17cd7669062c503" + integrity sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw== dependencies: - "@babel/helper-plugin-utils" "^7.27.1" + "@babel/helper-plugin-utils" "^7.28.6" "@babel/plugin-syntax-import-meta@^7.10.4": version "7.10.4" @@ -169,11 +181,11 @@ "@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== + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.28.6.tgz#f8ca28bbd84883b5fea0e447c635b81ba73997ee" + integrity sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w== dependencies: - "@babel/helper-plugin-utils" "^7.27.1" + "@babel/helper-plugin-utils" "^7.28.6" "@babel/plugin-syntax-logical-assignment-operators@^7.10.4": version "7.10.4" @@ -232,41 +244,41 @@ "@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" + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.28.6.tgz#c7b2ddf1d0a811145b1de800d1abd146af92e3a2" + integrity sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A== + dependencies: + "@babel/helper-plugin-utils" "^7.28.6" + +"@babel/template@^7.28.6", "@babel/template@^7.3.3": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.28.6.tgz#0e7e56ecedb78aeef66ce7972b082fce76a23e57" + integrity sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ== + dependencies: + "@babel/code-frame" "^7.28.6" + "@babel/parser" "^7.28.6" + "@babel/types" "^7.28.6" + +"@babel/traverse@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.28.6.tgz#871ddc79a80599a5030c53b1cc48cbe3a5583c2e" + integrity sha512-fgWX62k02qtjqdSNTAGxmKYY/7FSL9WAS1o2Hu5+I5m9T0yxZzr4cnrfXQ/MX0rIifthCSs6FKTlzYbJcPtMNg== + dependencies: + "@babel/code-frame" "^7.28.6" + "@babel/generator" "^7.28.6" + "@babel/helper-globals" "^7.28.0" + "@babel/parser" "^7.28.6" + "@babel/template" "^7.28.6" + "@babel/types" "^7.28.6" 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== +"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.28.2", "@babel/types@^7.28.6", "@babel/types@^7.3.3": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.28.6.tgz#c3e9377f1b155005bcc4c46020e7e394e13089df" + integrity sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg== dependencies: "@babel/helper-string-parser" "^7.27.1" - "@babel/helper-validator-identifier" "^7.27.1" + "@babel/helper-validator-identifier" "^7.28.5" "@bcoe/v8-coverage@^0.2.3": version "0.2.3" @@ -285,56 +297,239 @@ 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== +"@eslint-community/eslint-utils@^4.4.0", "@eslint-community/eslint-utils@^4.8.0": + version "4.9.1" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz#4e90af67bc51ddee6cdef5284edf572ec376b595" + integrity sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ== 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-community/regexpp@^4.10.0", "@eslint-community/regexpp@^4.12.1": + version "4.12.2" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.12.2.tgz#bccdf615bcf7b6e8db830ec0b8d21c9a25de597b" + integrity sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew== + +"@eslint/config-array@^0.21.2": + version "0.21.2" + resolved "https://registry.yarnpkg.com/@eslint/config-array/-/config-array-0.21.2.tgz#f29e22057ad5316cf23836cee9a34c81fffcb7e6" + integrity sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw== + dependencies: + "@eslint/object-schema" "^2.1.7" + debug "^4.3.1" + minimatch "^3.1.5" + +"@eslint/config-helpers@^0.4.2": + version "0.4.2" + resolved "https://registry.yarnpkg.com/@eslint/config-helpers/-/config-helpers-0.4.2.tgz#1bd006ceeb7e2e55b2b773ab318d300e1a66aeda" + integrity sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw== + dependencies: + "@eslint/core" "^0.17.0" + +"@eslint/core@^0.17.0": + version "0.17.0" + resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.17.0.tgz#77225820413d9617509da9342190a2019e78761c" + integrity sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ== + dependencies: + "@types/json-schema" "^7.0.15" -"@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== +"@eslint/eslintrc@^3.3.5": + version "3.3.5" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.3.5.tgz#c131793cfc1a7b96f24a83e0a8bbd4b881558c60" + integrity sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg== dependencies: - ajv "^6.12.4" + ajv "^6.14.0" debug "^4.3.2" - espree "^9.6.0" - globals "^13.19.0" + espree "^10.0.1" + globals "^14.0.0" ignore "^5.2.0" import-fresh "^3.2.1" - js-yaml "^4.1.0" - minimatch "^3.1.2" + js-yaml "^4.1.1" + minimatch "^3.1.5" 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== +"@eslint/js@9.39.4": + version "9.39.4" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.39.4.tgz#a3f83bfc6fd9bf33a853dfacd0b49b398eb596c1" + integrity sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw== -"@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== +"@eslint/object-schema@^2.1.7": + version "2.1.7" + resolved "https://registry.yarnpkg.com/@eslint/object-schema/-/object-schema-2.1.7.tgz#6e2126a1347e86a4dedf8706ec67ff8e107ebbad" + integrity sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA== + +"@eslint/plugin-kit@^0.4.1": + version "0.4.1" + resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz#9779e3fd9b7ee33571a57435cf4335a1794a6cb2" + integrity sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA== dependencies: - "@humanwhocodes/object-schema" "^2.0.3" - debug "^4.3.1" - minimatch "^3.0.5" + "@eslint/core" "^0.17.0" + levn "^0.4.1" + +"@hono/node-server@^1.19.10", "@hono/node-server@^1.19.9": + version "1.19.11" + resolved "https://registry.yarnpkg.com/@hono/node-server/-/node-server-1.19.11.tgz#dc419f0826dd2504e9fc86ad289d5636a0444e2f" + integrity sha512-dr8/3zEaB+p0D2n/IUrlPF1HZm586qgJNXK1a9fhg/PzdtkK7Ksd5l312tJX2yBuALqDYBlG20QEbayqPyxn+g== + +"@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.7" + resolved "https://registry.yarnpkg.com/@humanfs/node/-/node-0.16.7.tgz#822cb7b3a12c5a240a24f621b5a2413e27a45f26" + integrity sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ== + dependencies: + "@humanfs/core" "^0.19.1" + "@humanwhocodes/retry" "^0.4.0" "@humanwhocodes/module-importer@^1.0.1": version "1.0.1" resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== -"@humanwhocodes/object-schema@^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== +"@humanwhocodes/retry@^0.4.0", "@humanwhocodes/retry@^0.4.2": + version "0.4.3" + resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.4.3.tgz#c2b9d2e374ee62c586d3adbea87199b1d7a7a6ba" + integrity sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ== + +"@inquirer/checkbox@^3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@inquirer/checkbox/-/checkbox-3.0.1.tgz#0a57f704265f78c36e17f07e421b98efb4b9867b" + integrity sha512-0hm2nrToWUdD6/UHnel/UKGdk1//ke5zGUpHIvk5ZWmaKezlGxZkOJXNSWsdxO/rEqTkbB3lNC2J6nBElV2aAQ== + dependencies: + "@inquirer/core" "^9.2.1" + "@inquirer/figures" "^1.0.6" + "@inquirer/type" "^2.0.0" + ansi-escapes "^4.3.2" + yoctocolors-cjs "^2.1.2" + +"@inquirer/confirm@^4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@inquirer/confirm/-/confirm-4.0.1.tgz#9106d6bffa0b2fdd0e4f60319b6f04f2e06e6e25" + integrity sha512-46yL28o2NJ9doViqOy0VDcoTzng7rAb6yPQKU7VDLqkmbCaH4JqK4yk4XqlzNWy9PVC5pG1ZUXPBQv+VqnYs2w== + dependencies: + "@inquirer/core" "^9.2.1" + "@inquirer/type" "^2.0.0" + +"@inquirer/core@^9.2.1": + version "9.2.1" + resolved "https://registry.yarnpkg.com/@inquirer/core/-/core-9.2.1.tgz#677c49dee399c9063f31e0c93f0f37bddc67add1" + integrity sha512-F2VBt7W/mwqEU4bL0RnHNZmC/OxzNx9cOYxHqnXX3MP6ruYvZUZAW9imgN9+h/uBT/oP8Gh888J2OZSbjSeWcg== + dependencies: + "@inquirer/figures" "^1.0.6" + "@inquirer/type" "^2.0.0" + "@types/mute-stream" "^0.0.4" + "@types/node" "^22.5.5" + "@types/wrap-ansi" "^3.0.0" + ansi-escapes "^4.3.2" + cli-width "^4.1.0" + mute-stream "^1.0.0" + signal-exit "^4.1.0" + strip-ansi "^6.0.1" + wrap-ansi "^6.2.0" + yoctocolors-cjs "^2.1.2" + +"@inquirer/editor@^3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@inquirer/editor/-/editor-3.0.1.tgz#d109f21e050af6b960725388cb1c04214ed7c7bc" + integrity sha512-VA96GPFaSOVudjKFraokEEmUQg/Lub6OXvbIEZU1SDCmBzRkHGhxoFAVaF30nyiB4m5cEbDgiI2QRacXZ2hw9Q== + dependencies: + "@inquirer/core" "^9.2.1" + "@inquirer/type" "^2.0.0" + external-editor "^3.1.0" + +"@inquirer/expand@^3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@inquirer/expand/-/expand-3.0.1.tgz#aed9183cac4d12811be47a4a895ea8e82a17e22c" + integrity sha512-ToG8d6RIbnVpbdPdiN7BCxZGiHOTomOX94C2FaT5KOHupV40tKEDozp12res6cMIfRKrXLJyexAZhWVHgbALSQ== + dependencies: + "@inquirer/core" "^9.2.1" + "@inquirer/type" "^2.0.0" + yoctocolors-cjs "^2.1.2" + +"@inquirer/figures@^1.0.6": + version "1.0.15" + resolved "https://registry.yarnpkg.com/@inquirer/figures/-/figures-1.0.15.tgz#dbb49ed80df11df74268023b496ac5d9acd22b3a" + integrity sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g== + +"@inquirer/input@^3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@inquirer/input/-/input-3.0.1.tgz#de63d49e516487388508d42049deb70f2cb5f28e" + integrity sha512-BDuPBmpvi8eMCxqC5iacloWqv+5tQSJlUafYWUe31ow1BVXjW2a5qe3dh4X/Z25Wp22RwvcaLCc2siHobEOfzg== + dependencies: + "@inquirer/core" "^9.2.1" + "@inquirer/type" "^2.0.0" + +"@inquirer/number@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@inquirer/number/-/number-2.0.1.tgz#b9863080d02ab7dc2e56e16433d83abea0f2a980" + integrity sha512-QpR8jPhRjSmlr/mD2cw3IR8HRO7lSVOnqUvQa8scv1Lsr3xoAMMworcYW3J13z3ppjBFBD2ef1Ci6AE5Qn8goQ== + dependencies: + "@inquirer/core" "^9.2.1" + "@inquirer/type" "^2.0.0" + +"@inquirer/password@^3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@inquirer/password/-/password-3.0.1.tgz#2a9a9143591088336bbd573bcb05d5bf080dbf87" + integrity sha512-haoeEPUisD1NeE2IanLOiFr4wcTXGWrBOyAyPZi1FfLJuXOzNmxCJPgUrGYKVh+Y8hfGJenIfz5Wb/DkE9KkMQ== + dependencies: + "@inquirer/core" "^9.2.1" + "@inquirer/type" "^2.0.0" + ansi-escapes "^4.3.2" + +"@inquirer/prompts@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/@inquirer/prompts/-/prompts-6.0.1.tgz#43f5c0ed35c5ebfe52f1d43d46da2d363d950071" + integrity sha512-yl43JD/86CIj3Mz5mvvLJqAOfIup7ncxfJ0Btnl0/v5TouVUyeEdcpknfgc+yMevS/48oH9WAkkw93m7otLb/A== + dependencies: + "@inquirer/checkbox" "^3.0.1" + "@inquirer/confirm" "^4.0.1" + "@inquirer/editor" "^3.0.1" + "@inquirer/expand" "^3.0.1" + "@inquirer/input" "^3.0.1" + "@inquirer/number" "^2.0.1" + "@inquirer/password" "^3.0.1" + "@inquirer/rawlist" "^3.0.1" + "@inquirer/search" "^2.0.1" + "@inquirer/select" "^3.0.1" + +"@inquirer/rawlist@^3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@inquirer/rawlist/-/rawlist-3.0.1.tgz#729def358419cc929045f264131878ed379e0af3" + integrity sha512-VgRtFIwZInUzTiPLSfDXK5jLrnpkuSOh1ctfaoygKAdPqjcjKYmGh6sCY1pb0aGnCGsmhUxoqLDUAU0ud+lGXQ== + dependencies: + "@inquirer/core" "^9.2.1" + "@inquirer/type" "^2.0.0" + yoctocolors-cjs "^2.1.2" + +"@inquirer/search@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@inquirer/search/-/search-2.0.1.tgz#69b774a0a826de2e27b48981d01bc5ad81e73721" + integrity sha512-r5hBKZk3g5MkIzLVoSgE4evypGqtOannnB3PKTG9NRZxyFRKcfzrdxXXPcoJQsxJPzvdSU2Rn7pB7lw0GCmGAg== + dependencies: + "@inquirer/core" "^9.2.1" + "@inquirer/figures" "^1.0.6" + "@inquirer/type" "^2.0.0" + yoctocolors-cjs "^2.1.2" + +"@inquirer/select@^3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@inquirer/select/-/select-3.0.1.tgz#1df9ed27fb85a5f526d559ac5ce7cc4e9dc4e7ec" + integrity sha512-lUDGUxPhdWMkN/fHy1Lk7pF3nK1fh/gqeyWXmctefhxLYxlDsc7vsPBEpxrfVGDsVdyYJsiJoD4bJ1b623cV1Q== + dependencies: + "@inquirer/core" "^9.2.1" + "@inquirer/figures" "^1.0.6" + "@inquirer/type" "^2.0.0" + ansi-escapes "^4.3.2" + yoctocolors-cjs "^2.1.2" + +"@inquirer/type@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@inquirer/type/-/type-2.0.0.tgz#08fa513dca2cb6264fe1b0a2fabade051444e3f6" + integrity sha512-XvJRx+2KR3YXyYtPUUy+qd9i7p+GO9Ko6VIIpWlBrpWwXDv8WLFeHTxz35CfQFUiBMLXlGHhGzys7lqit9gWag== + dependencies: + mute-stream "^1.0.0" "@istanbuljs/load-nyc-config@^1.0.0": version "1.1.0" @@ -544,13 +739,20 @@ "@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== +"@jridgewell/gen-mapping@^0.3.12", "@jridgewell/gen-mapping@^0.3.5": + version "0.3.13" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz#6342a19f44347518c93e43b1ac69deb3c4656a1f" + integrity sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA== dependencies: - "@jridgewell/set-array" "^1.2.1" - "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/sourcemap-codec" "^1.5.0" + "@jridgewell/trace-mapping" "^0.3.24" + +"@jridgewell/remapping@^2.3.5": + version "2.3.5" + resolved "https://registry.yarnpkg.com/@jridgewell/remapping/-/remapping-2.3.5.tgz#375c476d1972947851ba1e15ae8f123047445aa1" + integrity sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ== + dependencies: + "@jridgewell/gen-mapping" "^0.3.5" "@jridgewell/trace-mapping" "^0.3.24" "@jridgewell/resolve-uri@^3.0.3", "@jridgewell/resolve-uri@^3.1.0": @@ -558,15 +760,10 @@ 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/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.5.0": + version "1.5.5" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz#6912b00d2c631c0d15ce1a7ab57cd657f2a8f8ba" + integrity sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og== "@jridgewell/trace-mapping@0.3.9": version "0.3.9" @@ -576,29 +773,36 @@ "@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== +"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.28": + version "0.3.31" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz#db15d6781c931f3a251a3dac39501c98a6082fd0" + integrity sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw== dependencies: "@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.27.1": + version "1.27.1" + resolved "https://registry.yarnpkg.com/@modelcontextprotocol/sdk/-/sdk-1.27.1.tgz#a602cf823bf8a68e13e7112f50aeb02b09fb83b9" + integrity sha512-sr6GbP+4edBwFndLbM60gf07z0FQ79gaExpnsjMGePXqFcSSb7t6iscpjk9DhFhwd+mTEQrzNafGP8/iGGFYaA== dependencies: + "@hono/node-server" "^1.19.9" + ajv "^8.17.1" + ajv-formats "^3.0.1" content-type "^1.0.5" cors "^2.8.5" - cross-spawn "^7.0.3" + cross-spawn "^7.0.5" eventsource "^3.0.2" - express "^5.0.1" - express-rate-limit "^7.5.0" + eventsource-parser "^3.0.0" + express "^5.2.1" + express-rate-limit "^8.2.1" + hono "^4.11.4" + jose "^6.1.3" + json-schema-typed "^8.0.2" pkce-challenge "^5.0.0" raw-body "^3.0.0" - zod "^3.23.8" - zod-to-json-schema "^3.24.1" + zod "^3.25 || ^4.0" + zod-to-json-schema "^3.25.1" "@nodelib/fs.scandir@2.1.5": version "2.1.5" @@ -613,7 +817,7 @@ resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== -"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": +"@nodelib/fs.walk@^1.2.3": version "1.2.8" resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== @@ -621,10 +825,15 @@ "@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== +"@pinojs/redact@^0.4.0": + version "0.4.0" + resolved "https://registry.yarnpkg.com/@pinojs/redact/-/redact-0.4.0.tgz#c3de060dd12640dcc838516aa2a6803cc7b2e9d6" + integrity sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg== + +"@pkgr/core@^0.2.9": + version "0.2.9" + resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.2.9.tgz#d229a7b7f9dac167a156992ef23c7f023653f53b" + integrity sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA== "@sinclair/typebox@^0.27.8": version "0.27.8" @@ -656,9 +865,9 @@ 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== + version "1.0.12" + resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.12.tgz#be57ceac1e4692b41be9de6be8c32a106636dba4" + integrity sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ== "@tsconfig/node12@^1.0.7": version "1.0.11" @@ -702,11 +911,62 @@ "@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== + version "7.28.0" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.28.0.tgz#07d713d6cce0d265c9849db0cbe62d3f61f36f74" + integrity sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q== dependencies: - "@babel/types" "^7.20.7" + "@babel/types" "^7.28.2" + +"@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/cookie-parser@^1.4.10": + version "1.4.10" + resolved "https://registry.yarnpkg.com/@types/cookie-parser/-/cookie-parser-1.4.10.tgz#a045272a383a30597a01955d4f9c790018f214e4" + integrity sha512-B4xqkqfZ8Wek+rCOeRxsjMS9OgvzebEzzLYw7NHYuvzb7IdxOkI0ZHGgeEBX4PUM7QGVvNSK60T3OvWj3YfBRg== + +"@types/cors@^2.8.19": + version "2.8.19" + resolved "https://registry.yarnpkg.com/@types/cors/-/cors-2.8.19.tgz#d93ea2673fd8c9f697367f5eeefc2bbfa94f0342" + integrity sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg== + dependencies: + "@types/node" "*" + +"@types/estree@^1.0.6": + version "1.0.8" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.8.tgz#958b91c991b1867ced318bedea0e215ee050726e" + integrity sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w== + +"@types/express-serve-static-core@^5.0.0": + version "5.1.1" + resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-5.1.1.tgz#1a77faffee9572d39124933259be2523837d7eaa" + integrity sha512-v4zIMr/cX7/d2BpAEX3KNKL/JrT1s43s96lLvvdTmza1oEvDudCqK9aF/djc/SWgy8Yh0h30TZx5VpzqFCxk5A== + dependencies: + "@types/node" "*" + "@types/qs" "*" + "@types/range-parser" "*" + "@types/send" "*" + +"@types/express@^5.0.3": + version "5.0.6" + resolved "https://registry.yarnpkg.com/@types/express/-/express-5.0.6.tgz#2d724b2c990dcb8c8444063f3580a903f6d500cc" + integrity sha512-sKYVuV7Sv9fbPIt/442koC7+IIwK5olP1KWeD88e/idgoJqDm3JV/YUiPwkoKK92ylff2MGxSz1CSjsXelx0YA== + dependencies: + "@types/body-parser" "*" + "@types/express-serve-static-core" "^5.0.0" + "@types/serve-static" "^2" "@types/graceful-fs@^4.1.3": version "4.1.9" @@ -715,6 +975,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,27 +1007,76 @@ 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/mute-stream@^0.0.4": + version "0.0.4" + resolved "https://registry.yarnpkg.com/@types/mute-stream/-/mute-stream-0.0.4.tgz#77208e56a08767af6c5e1237be8888e2f255c478" + integrity sha512-CPM9nzrCPPJHQNA9keH9CVkVI+WR5kMa+7XEs5jcGQ0VoAGnLv242w8lIVgwAEfmE4oufJRaTc9PNLQl0ioAow== + dependencies: + "@types/node" "*" + "@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== + version "25.0.8" + resolved "https://registry.yarnpkg.com/@types/node/-/node-25.0.8.tgz#e54e00f94fe1db2497b3e42d292b8376a2678c8d" + integrity sha512-powIePYMmC3ibL0UJ2i2s0WIbq6cg6UyVFQxSCpaPxxzAaziRfimGivjdF943sSGV6RADVbk0Nvlm5P/FB44Zg== + dependencies: + undici-types "~7.16.0" + +"@types/node@^22.5.5": + version "22.19.6" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.19.6.tgz#0e9d80ebcd2dfce03265768c17a1212d4eb07e82" + integrity sha512-qm+G8HuG6hOHQigsi7VGuLjUVu6TtBo/F05zvX04Mw2uCg9Dv0Qxy3Qw7j41SidlTcl5D/5yg0SEZqOB+EqZnQ== dependencies: undici-types "~6.21.0" +"@types/qs@*", "@types/qs@^6.14.0": + 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 "1.2.1" + resolved "https://registry.yarnpkg.com/@types/send/-/send-1.2.1.tgz#6a784e45543c18c774c049bff6d3dbaf045c9c74" + integrity sha512-arsCikDvlU99zl1g69TcAB3mzZPpxgw0UQnaHeC1Nwb015xp8bknZv5rIfri9xTOcMuaVgvabfIRA7PSZVuZIQ== + dependencies: + "@types/node" "*" + +"@types/serve-static@^2": + version "2.2.0" + resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-2.2.0.tgz#d4a447503ead0d1671132d1ab6bd58b805d8de6a" + integrity sha512-8mam4H1NHLtu7nmtalF7eyBH14QyOASmcxHhSfEoRyr0nP/YdoesEtU+uSRvMe96TW/HPTtkoKqQLl53N7UXMQ== + dependencies: + "@types/http-errors" "*" + "@types/node" "*" + "@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/wrap-ansi@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/wrap-ansi/-/wrap-ansi-3.0.0.tgz#18b97a972f94f60a679fd5c796d96421b9abb9fd" + integrity sha512-ltIpx+kM7g/MLRZfkbL7EsCEjfzCcScLpkg37eXEtx5kmrAKBkTJwd1GIAjDSL8wTpM6Hzn5YO4pSb91BEwu1g== + "@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== + version "17.0.35" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.35.tgz#07013e46aa4d7d7d50a49e15604c1c5340d4eb24" + integrity sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg== dependencies: "@types/yargs-parser" "*" @@ -847,10 +1161,10 @@ "@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== +"@valtown/deno-http-worker@^0.0.21": + version "0.0.21" + resolved "https://registry.yarnpkg.com/@valtown/deno-http-worker/-/deno-http-worker-0.0.21.tgz#9ce3b5c1d0db211fe7ea8297881fe551838474ad" + integrity sha512-16kFuUykann75lNytnXXIQlmpzreZjzdyT27ebT3yNGCS3kKaS1iZYWHc3Si9An54Cphwr4qEcviChQkEeJBlA== accepts@^2.0.0: version "2.0.0" @@ -872,10 +1186,15 @@ acorn-walk@^8.1.1: 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== +acorn@^8.11.0, acorn@^8.4.1: + version "8.15.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.15.0.tgz#a360898bc415edaac46c8241f6383975b930b816" + integrity sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg== + +acorn@^8.15.0: + version "8.16.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.16.0.tgz#4ce79c89be40afe7afe8f3adb902a1f1ce9ac08a" + integrity sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw== aggregate-error@^3.0.0: version "3.1.0" @@ -885,17 +1204,44 @@ aggregate-error@^3.0.0: 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== +ajv-formats@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/ajv-formats/-/ajv-formats-3.0.1.tgz#3d5dc762bca17679c3c2ea7e90ad6b7532309578" + integrity sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ== + dependencies: + ajv "^8.0.0" + +ajv@^6.14.0: + version "6.14.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.14.0.tgz#fd067713e228210636ebb08c60bd3765d6dbe73a" + integrity sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw== 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: +ajv@^8.0.0, ajv@^8.17.1: + version "8.17.1" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.17.1.tgz#37d9a5c776af6bc92d7f4f9510eba4c0a60d11a6" + integrity sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g== + dependencies: + fast-deep-equal "^3.1.3" + fast-uri "^3.0.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + +ajv@^8.18.0: + version "8.18.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.18.0.tgz#8864186b6738d003eb3a933172bb3833e10cefbc" + integrity sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A== + dependencies: + fast-deep-equal "^3.1.3" + fast-uri "^3.0.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + +ansi-escapes@^4.2.1, ansi-escapes@^4.3.2: 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== @@ -944,10 +1290,10 @@ argparse@^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== +atomic-sleep@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/atomic-sleep/-/atomic-sleep-1.0.0.tgz#eb85b77a601fc932cfe432c5acd364a9e2c9075b" + integrity sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ== babel-jest@^29.7.0: version "29.7.0" @@ -984,9 +1330,9 @@ babel-plugin-jest-hoist@^29.6.3: "@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== + version "1.2.0" + resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz#20730d6cdc7dda5d89401cab10ac6a32067acde6" + integrity sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg== dependencies: "@babel/plugin-syntax-async-generators" "^7.8.4" "@babel/plugin-syntax-bigint" "^7.8.3" @@ -1017,33 +1363,38 @@ balanced-match@^1.0.0: 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== +baseline-browser-mapping@^2.9.0: + version "2.9.14" + resolved "https://registry.yarnpkg.com/baseline-browser-mapping/-/baseline-browser-mapping-2.9.14.tgz#3b6af0bc032445bca04de58caa9a87cfe921cbb3" + integrity sha512-B0xUquLkiGLgHhpPBqvl7GWegWBUNuujQ6kXd/r1U38ElPT6Ok8KZ8e+FpUGEc2ZoRQUzq/aUnaKFc/svWUGSg== + +body-parser@^2.2.1: + version "2.2.2" + resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-2.2.2.tgz#1a32cdb966beaf68de50a9dfbe5b58f83cb8890c" + integrity sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA== dependencies: bytes "^3.1.2" content-type "^1.0.5" - debug "^4.4.0" + debug "^4.4.3" http-errors "^2.0.0" - iconv-lite "^0.6.3" + iconv-lite "^0.7.0" on-finished "^2.4.1" - qs "^6.14.0" - raw-body "^3.0.0" - type-is "^2.0.0" + qs "^6.14.1" + raw-body "^3.0.1" + type-is "^2.0.1" 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== + version "1.1.12" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.12.tgz#ab9b454466e5a8cc3a187beaad580412a9c5b843" + integrity sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg== 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== + version "2.0.2" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.2.tgz#54fc53237a613d854c7bd37463aad17df87214e7" + integrity sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ== dependencies: balanced-match "^1.0.0" @@ -1055,14 +1406,15 @@ braces@^3.0.3: 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== + version "4.28.1" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.28.1.tgz#7f534594628c53c63101079e27e40de490456a95" + integrity sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA== dependencies: - caniuse-lite "^1.0.30001716" - electron-to-chromium "^1.5.149" - node-releases "^2.0.19" - update-browserslist-db "^1.1.3" + baseline-browser-mapping "^2.9.0" + caniuse-lite "^1.0.30001759" + electron-to-chromium "^1.5.263" + node-releases "^2.0.27" + update-browserslist-db "^1.2.0" bs-logger@^0.2.6: version "0.2.6" @@ -1083,7 +1435,7 @@ buffer-from@^1.0.0: resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== -bytes@3.1.2, bytes@^3.1.2: +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== @@ -1119,12 +1471,12 @@ camelcase@^6.2.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== +caniuse-lite@^1.0.30001759: + version "1.0.30001764" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001764.tgz#03206c56469f236103b90f9ae10bcb8b9e1f6005" + integrity sha512-9JGuzl2M+vPL+pz70gtMF9sHdMFbY9FJaQBi186cHKH3pSzDvzoUJUPV6fqiKIMyXbud9ZLg4F3Yza1vJ1+93g== -chalk@^4.0.0, chalk@^4.0.2: +chalk@^4.0.0: version "4.1.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== @@ -1137,6 +1489,11 @@ char-regex@^1.0.2: resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== +chardet@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" + integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== + ci-info@^3.2.0: version "3.9.0" resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" @@ -1152,6 +1509,11 @@ clean-stack@^2.0.0: resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== +cli-width@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-4.1.0.tgz#42daac41d3c254ef38ad8ac037672130173691c5" + integrity sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ== + cliui@^8.0.1: version "8.0.1" resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" @@ -1172,9 +1534,9 @@ code-block-writer@^12.0.0: 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== + version "1.0.3" + resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.3.tgz#cc1f01eb8d02298cbc9a437c74c70ab4e5210b80" + integrity sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw== color-convert@^2.0.1: version "2.0.1" @@ -1188,17 +1550,25 @@ 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== +colorette@^2.0.7: + version "2.0.20" + resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.20.tgz#9eb793e6833067f7235902fcd3b09917a000a95a" + integrity sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w== + +commander@^13.1.0: + version "13.1.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-13.1.0.tgz#776167db68c78f38dcce1f9b8d7b8b9a488abf46" + integrity sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw== + 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" + version "1.0.1" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-1.0.1.tgz#a8b7bbeb2904befdfb6787e5c0c086959f605f9b" + integrity sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q== content-type@^1.0.5: version "1.0.5" @@ -1210,12 +1580,25 @@ convert-source-map@^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-parser@^1.4.6: + version "1.4.7" + resolved "https://registry.yarnpkg.com/cookie-parser/-/cookie-parser-1.4.7.tgz#e2125635dfd766888ffe90d60c286404fa0e7b26" + integrity sha512-nGUvgXnotP3BsjiLX2ypbQnWoGUPIIfHQNZkkC668ntrzGWEZVW70HDEB1qnNGMicPje6EttlIgzo51YSwNQGw== + dependencies: + cookie "0.7.2" + cookie-signature "1.0.6" + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== + 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: +cookie@0.7.2, cookie@^0.7.1: version "0.7.2" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.7.2.tgz#556369c472a2ba910f2979891b526b3436237ed7" integrity sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w== @@ -1246,7 +1629,7 @@ create-require@^1.1.0: resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== -cross-spawn@^7.0.2, cross-spawn@^7.0.3: +cross-spawn@^7.0.3, cross-spawn@^7.0.5, 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== @@ -1255,17 +1638,22 @@ cross-spawn@^7.0.2, cross-spawn@^7.0.3: 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== +dateformat@^4.6.3: + version "4.6.3" + resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-4.6.3.tgz#556fa6497e5217fedb78821424f8a1c22fa3f4b5" + integrity sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA== + +debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.7, debug@^4.4.0, debug@^4.4.3: + version "4.4.3" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.3.tgz#c6ae432d9bd9662582fce08709b038c58e9e3d6a" + integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA== 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== + version "1.7.1" + resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.7.1.tgz#364661eea3d73f3faba7089214420ec2f8f13e15" + integrity sha512-9JmrhGZpOlEgOLdQgSm0zxFaYoQon408V1v49aqTWuXENVlnCuY9JBZcXZiCsZQWDjTm5Qf/nIvAy77mXDAjEg== deep-is@^0.1.3: version "0.1.4" @@ -1277,7 +1665,7 @@ 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== -depd@2.0.0, depd@^2.0.0: +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== @@ -1297,13 +1685,6 @@ diff@^4.0.1: 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" @@ -1318,17 +1699,10 @@ ee-first@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== +electron-to-chromium@^1.5.263: + version "1.5.267" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.267.tgz#5d84f2df8cdb6bfe7e873706bb21bd4bfb574dc7" + integrity sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw== emittery@^0.13.1: version "0.13.1" @@ -1345,10 +1719,17 @@ encodeurl@^2.0.0: resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-2.0.0.tgz#7b8ea898077d7e409d3ac45474ea38eaf0857a58" integrity sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg== +end-of-stream@^1.1.0: + version "1.4.5" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.5.tgz#7344d711dea40e0b74abc2ed49778743ccedb08c" + integrity sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg== + dependencies: + once "^1.4.0" + 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== + version "1.3.4" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.4.tgz#b3a8d8bb6f92eecc1629e3e27d3c8607a8a32414" + integrity sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ== dependencies: is-arrayish "^0.2.1" @@ -1389,106 +1770,95 @@ escape-string-regexp@^4.0.0: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== -eslint-plugin-prettier@^5.0.1: - version "5.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== +eslint-plugin-prettier@^5.4.1: + version "5.5.5" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.5.5.tgz#9eae11593faa108859c26f9a9c367d619a0769c0" + integrity sha512-hscXkbqUZ2sPithAuLm5MXL+Wph+U7wHngPBv9OMWwlP8iaflyxpjTYZkmdgB4/vPIhemRlBEoLrH7UC1n7aUw== dependencies: - eslint-rule-composer "^0.3.0" + prettier-linter-helpers "^1.0.1" + synckit "^0.11.12" -eslint-rule-composer@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/eslint-rule-composer/-/eslint-rule-composer-0.3.0.tgz#79320c927b0c5c0d3d3d2b76c8b4a488f25bbaf9" - integrity sha512-bt+Sh8CtDmn2OajxvNO+BX7Wn4CIWMpTRm3MaiKPCQcnnlm0CS2mhui6QaoeQugs+3Kj2ESKEEGJUdVafwhiCg== +eslint-plugin-unused-imports@^4.1.4: + version "4.4.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-4.4.1.tgz#a831f0a2937d7631eba30cb87091ab7d3a5da0e1" + integrity sha512-oZGYUz1X3sRMGUB+0cZyK2VcvRX5lm/vB56PgNNcU+7ficUCKm66oZWKUubXWnOuPjQ8PvmXtCViXBMONPe7tQ== -eslint-scope@^7.2.2: - version "7.2.2" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f" - integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== +eslint-scope@^8.4.0: + version "8.4.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-8.4.0.tgz#88e646a207fad61436ffa39eb505147200655c82" + integrity sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg== dependencies: esrecurse "^4.3.0" estraverse "^5.2.0" -eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: +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" +eslint-visitor-keys@^4.2.0, eslint-visitor-keys@^4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz#4cfea60fe7dd0ad8e816e1ed026c1d5251b512c1" + integrity sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ== + +eslint@^9.39.1: + version "9.39.4" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.39.4.tgz#855da1b2e2ad66dc5991195f35e262bcec8117b5" + integrity sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ== + dependencies: + "@eslint-community/eslint-utils" "^4.8.0" + "@eslint-community/regexpp" "^4.12.1" + "@eslint/config-array" "^0.21.2" + "@eslint/config-helpers" "^0.4.2" + "@eslint/core" "^0.17.0" + "@eslint/eslintrc" "^3.3.5" + "@eslint/js" "9.39.4" + "@eslint/plugin-kit" "^0.4.1" + "@humanfs/node" "^0.16.6" "@humanwhocodes/module-importer" "^1.0.1" - "@nodelib/fs.walk" "^1.2.8" - "@ungap/structured-clone" "^1.2.0" - ajv "^6.12.4" + "@humanwhocodes/retry" "^0.4.2" + "@types/estree" "^1.0.6" + ajv "^6.14.0" chalk "^4.0.0" - cross-spawn "^7.0.2" + cross-spawn "^7.0.6" debug "^4.3.2" - doctrine "^3.0.0" escape-string-regexp "^4.0.0" - eslint-scope "^7.2.2" - eslint-visitor-keys "^3.4.3" - espree "^9.6.1" - esquery "^1.4.2" + eslint-scope "^8.4.0" + eslint-visitor-keys "^4.2.1" + espree "^10.4.0" + esquery "^1.5.0" esutils "^2.0.2" fast-deep-equal "^3.1.3" - file-entry-cache "^6.0.1" + file-entry-cache "^8.0.0" find-up "^5.0.0" glob-parent "^6.0.2" - globals "^13.19.0" - graphemer "^1.4.0" ignore "^5.2.0" imurmurhash "^0.1.4" is-glob "^4.0.0" - is-path-inside "^3.0.3" - js-yaml "^4.1.0" json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.4.1" lodash.merge "^4.6.2" - minimatch "^3.1.2" + minimatch "^3.1.5" natural-compare "^1.4.0" optionator "^0.9.3" - strip-ansi "^6.0.1" - text-table "^0.2.0" -espree@^9.6.0, espree@^9.6.1: - version "9.6.1" - resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f" - integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== +espree@^10.0.1, espree@^10.4.0: + version "10.4.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-10.4.0.tgz#d54f4949d4629005a1fa168d937c3ff1f7e2a837" + integrity sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ== dependencies: - acorn "^8.9.0" + acorn "^8.15.0" acorn-jsx "^5.3.2" - eslint-visitor-keys "^3.4.1" + eslint-visitor-keys "^4.2.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== +esquery@^1.5.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.7.0.tgz#08d048f261f0ddedb5bae95f46809463d9c9496d" + integrity sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g== dependencies: estraverse "^5.1.0" @@ -1514,10 +1884,10 @@ 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.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/eventsource-parser/-/eventsource-parser-3.0.1.tgz#5e358dba9a55ba64ca90da883c4ca35bd82467bd" - integrity sha512-VARTJ9CYeuQYb0pZEPbzi740OWFgpHe7AYJ2WFZVnUDUQp5Dk2yJUgF36YsZ81cOyxT0QxmXD2EQpapAouzWVA== +eventsource-parser@^3.0.0, eventsource-parser@^3.0.1: + version "3.0.6" + resolved "https://registry.yarnpkg.com/eventsource-parser/-/eventsource-parser-3.0.6.tgz#292e165e34cacbc936c3c92719ef326d4aeb4e90" + integrity sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg== eventsource@^3.0.2: version "3.0.7" @@ -1557,23 +1927,26 @@ expect@^29.0.0, expect@^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-rate-limit@^8.2.1: + version "8.3.1" + resolved "https://registry.yarnpkg.com/express-rate-limit/-/express-rate-limit-8.3.1.tgz#0aaba098eadd40f6737f30a98e6b16fa1a29edfb" + integrity sha512-D1dKN+cmyPWuvB+G2SREQDzPY1agpBIcTa9sJxOPMCNeH3gwzhqJRDWCXW3gg0y//+LQ/8j52JbMROWyrKdMdw== + dependencies: + ip-address "10.1.0" -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== +express@^5.1.0, express@^5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/express/-/express-5.2.1.tgz#8f21d15b6d327f92b4794ecf8cb08a72f956ac04" + integrity sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw== dependencies: accepts "^2.0.0" - body-parser "^2.2.0" + body-parser "^2.2.1" content-disposition "^1.0.0" content-type "^1.0.5" cookie "^0.7.1" cookie-signature "^1.2.1" debug "^4.4.0" + depd "^2.0.0" encodeurl "^2.0.0" escape-html "^1.0.3" etag "^1.8.1" @@ -1595,6 +1968,20 @@ express@^5.0.1: type-is "^2.0.1" vary "^1.1.2" +external-editor@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" + integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== + dependencies: + chardet "^0.7.0" + iconv-lite "^0.4.24" + tmp "^0.0.33" + +fast-copy@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/fast-copy/-/fast-copy-4.0.2.tgz#57f14115e1edbec274f69090072a480aa29cbedd" + integrity sha512-ybA6PDXIXOXivLJK/z9e+Otk7ve13I4ckBvGO5I2RRmBU1gMHLVDJYEuJYhGwez7YNlYji2M2DvVU+a9mSFDlw== + 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" @@ -1626,10 +2013,20 @@ fast-levenshtein@^2.0.6: resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== +fast-safe-stringify@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz#c406a83b6e70d9e35ce3b30a81141df30aeba884" + integrity sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA== + +fast-uri@^3.0.1: + version "3.1.0" + resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-3.1.0.tgz#66eecff6c764c0df9b762e62ca7edcfb53b4edfa" + integrity sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA== + 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== + version "1.20.1" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.20.1.tgz#ca750a10dc925bc8b18839fd203e3ef4b3ced675" + integrity sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw== dependencies: reusify "^1.0.4" @@ -1640,19 +2037,17 @@ fb-watchman@^2.0.0: dependencies: bser "2.1.1" -file-entry-cache@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" - integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== - dependencies: - flat-cache "^3.0.4" +fflate@^0.8.2: + version "0.8.2" + resolved "https://registry.yarnpkg.com/fflate/-/fflate-0.8.2.tgz#fc8631f5347812ad6028bbe4a2308b2792aa1dea" + integrity sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A== -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== +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: - minimatch "^5.0.1" + flat-cache "^4.0.0" fill-range@^7.1.1: version "7.1.1" @@ -1662,9 +2057,9 @@ fill-range@^7.1.1: 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== + version "2.1.1" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-2.1.1.tgz#a2c517a6559852bcdb06d1f8bd7f51b68fad8099" + integrity sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA== dependencies: debug "^4.4.0" encodeurl "^2.0.0" @@ -1689,20 +2084,27 @@ find-up@^5.0.0: 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== +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.3" - rimraf "^3.0.2" + keyv "^4.5.4" 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== +flora-colossus@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/flora-colossus/-/flora-colossus-2.0.0.tgz#af1e85db0a8256ef05f3fb531c1235236c97220a" + integrity sha512-dz4HxH6pOvbUzZpZ/yXhafjbR2I8cenK5xL0KtBFb7U2ADsR+OwXifnxZjij/pZWF775uSCMzWVd+jDik2H2IA== + dependencies: + debug "^4.3.4" + fs-extra "^10.1.0" + forwarded@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.2.0.tgz#2269936428aad4c15c7ebe9779a84bf0b2a81811" @@ -1713,6 +2115,15 @@ fresh@^2.0.0: resolved "https://registry.yarnpkg.com/fresh/-/fresh-2.0.0.tgz#8dd7df6a1b3a1b3a5cf186c05a5dd267622635a4" integrity sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A== +fs-extra@^10.1.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf" + integrity sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ== + dependencies: + graceful-fs "^4.2.0" + jsonfile "^6.0.1" + universalify "^2.0.0" + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -1728,6 +2139,20 @@ function-bind@^1.1.2: resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== +fuse.js@^7.1.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/fuse.js/-/fuse.js-7.1.0.tgz#306228b4befeee11e05b027087c2744158527d09" + integrity sha512-trLf4SzuuUxfusZADLINj+dE8clK1frKdmqiJNb1Es75fmI5oY6X2mxLVUciLLjxqw/xr72Dhy+lER6dGd02FQ== + +galactus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/galactus/-/galactus-1.0.0.tgz#c2615182afa0c6d0859b92e56ae36d052827db7e" + integrity sha512-R1fam6D4CyKQGNlvJne4dkNF+PvUUl7TAJInvTGa9fti9qAv95quQz29GXapA4d8Ec266mJJxFVh82M4GIIGDQ== + dependencies: + debug "^4.3.4" + flora-colossus "^2.0.0" + fs-extra "^10.1.0" + 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" @@ -1803,24 +2228,17 @@ glob@^7.1.3, glob@^7.1.4: 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" +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== 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: +graceful-fs@^4.1.6, graceful-fs@^4.2.0, 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== @@ -1830,6 +2248,18 @@ graphemer@^1.4.0: resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== +handlebars@^4.7.8: + version "4.7.8" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.8.tgz#41c42c18b1be2365439188c77c6afae71c0cd9e9" + integrity sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ== + dependencies: + minimist "^1.2.5" + neo-async "^2.6.2" + source-map "^0.6.1" + wordwrap "^1.0.0" + optionalDependencies: + uglify-js "^3.1.4" + has-flag@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" @@ -1847,31 +2277,48 @@ hasown@^2.0.2: dependencies: function-bind "^1.1.2" +help-me@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/help-me/-/help-me-5.0.0.tgz#b1ebe63b967b74060027c2ac61f9be12d354a6f6" + integrity sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg== + +hono@^4.11.4, hono@^4.12.4: + version "4.12.7" + resolved "https://registry.yarnpkg.com/hono/-/hono-4.12.7.tgz#ca000956e965c2b3d791e43540498e616d6c6442" + integrity sha512-jq9l1DM0zVIvsm3lv9Nw9nlJnMNPOcAtsbsgiUhWcFzPE99Gvo6yRTlszSLLYacMeQ6quHD6hMfId8crVHvexw== + 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== +http-errors@^2.0.0, http-errors@^2.0.1, http-errors@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.1.tgz#36d2f65bc909c8790018dd36fb4d93da6caae06b" + integrity sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ== dependencies: - depd "2.0.0" - inherits "2.0.4" - setprototypeof "1.2.0" - statuses "2.0.1" - toidentifier "1.0.1" + depd "~2.0.0" + inherits "~2.0.4" + setprototypeof "~1.2.0" + statuses "~2.0.2" + 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== +iconv-lite@^0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + +iconv-lite@^0.7.0, iconv-lite@~0.7.0: + version "0.7.2" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.7.2.tgz#d0bdeac3f12b4835b7359c2ad89c422a4d1cc72e" + integrity sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw== dependencies: safer-buffer ">= 2.1.2 < 3.0.0" @@ -1880,6 +2327,11 @@ ignore@^5.2.0, ignore@^5.3.1: resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== +ignore@^7.0.5: + version "7.0.5" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-7.0.5.tgz#4cb5f6cd7d4c7ab0365738c7aea888baa6d7efd9" + integrity sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg== + import-fresh@^3.2.1: version "3.3.1" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.1.tgz#9cecb56503c0ada1f2741dbbd6546e4b13b57ccf" @@ -1914,11 +2366,16 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.4, inherits@^2.0.3: +inherits@2, inherits@^2.0.3, inherits@~2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== +ip-address@10.1.0: + version "10.1.0" + resolved "https://registry.yarnpkg.com/ip-address/-/ip-address-10.1.0.tgz#d8dcffb34d0e02eb241427444a6e23f5b0595aa4" + integrity sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q== + ipaddr.js@1.9.1: version "1.9.1" resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" @@ -1929,7 +2386,7 @@ is-arrayish@^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: +is-core-module@^2.16.1: version "2.16.1" resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.16.1.tgz#2a98801a849f43e2add644fbb6bc6229b19a4ef4" integrity sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w== @@ -1963,11 +2420,6 @@ is-number@^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" @@ -2029,23 +2481,13 @@ istanbul-lib-source-maps@^4.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== + version "3.2.0" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.2.0.tgz#cb4535162b5784aa623cee21a7252cf2c807ac93" + integrity sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA== 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" @@ -2346,7 +2788,7 @@ jest-snapshot@^29.7.0: pretty-format "^29.7.0" semver "^7.5.3" -jest-util@^29.0.0, jest-util@^29.7.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== @@ -2404,23 +2846,37 @@ jest@^29.4.0: import-local "^3.0.2" jest-cli "^29.7.0" +jose@^6.1.3: + version "6.2.1" + resolved "https://registry.yarnpkg.com/jose/-/jose-6.2.1.tgz#7a6b1de83816deaee9055a558e1278a7b2b9ea1b" + integrity sha512-jUaKr1yrbfaImV7R2TN/b3IcZzsw38/chqMpo2XJ7i2F8AfM/lA4G1goC3JVEwg0H7UldTmSt3P68nt31W7/mw== + +joycon@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/joycon/-/joycon-3.1.1.tgz#bce8596d6ae808f8b68168f5fc69280996894f03" + integrity sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw== + +"jq-web@https://github.com/stainless-api/jq-web/releases/download/v0.8.8/jq-web.tar.gz": + version "0.8.8" + resolved "https://github.com/stainless-api/jq-web/releases/download/v0.8.8/jq-web.tar.gz#7849ef64bdfc28f70cbfc9888f886860e96da10d" + 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== + version "3.14.2" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.2.tgz#77485ce1dd7f33c061fd1b16ecea23b55fcb04b0" + integrity sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg== 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== +js-yaml@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.1.tgz#854c292467705b699476e1a2decc0c8a3458806b" + integrity sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA== dependencies: argparse "^2.0.1" @@ -2444,6 +2900,16 @@ json-schema-traverse@^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-schema-traverse@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" + integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== + +json-schema-typed@^8.0.2: + version "8.0.2" + resolved "https://registry.yarnpkg.com/json-schema-typed/-/json-schema-typed-8.0.2.tgz#e98ee7b1899ff4a184534d1f167c288c66bbeff4" + integrity sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA== + 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" @@ -2454,7 +2920,16 @@ json5@^2.2.2, json5@^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: +jsonfile@^6.0.1: + version "6.2.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.2.0.tgz#7c265bd1b65de6977478300087c99f1c84383f62" + integrity sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg== + dependencies: + universalify "^2.0.0" + optionalDependencies: + graceful-fs "^4.1.6" + +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== @@ -2572,10 +3047,10 @@ mime-db@^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== +mime-types@^3.0.0, mime-types@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-3.0.2.tgz#39002d4182575d5af036ffa118100f2524b2e2ab" + integrity sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A== dependencies: mime-db "^1.54.0" @@ -2584,20 +3059,13 @@ mimic-fn@^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== +minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.5: + version "3.1.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.5.tgz#580c88f8d5445f2bd6aa8f3cadefa0de79fbd69e" + integrity sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w== 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" @@ -2612,7 +3080,7 @@ minimatch@^9.0.4: dependencies: brace-expansion "^2.0.1" -minimist@^1.2.6: +minimist@^1.2.5, minimist@^1.2.6: version "1.2.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== @@ -2627,6 +3095,11 @@ ms@^2.1.3: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== +mute-stream@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-1.0.0.tgz#e31bd9fe62f0aed23520aa4324ea6671531e013e" + integrity sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA== + natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" @@ -2637,15 +3110,25 @@ negotiator@^1.0.0: resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-1.0.0.tgz#b6c91bb47172d69f93cfd7c357bbb529019b5f6a" integrity sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg== +neo-async@^2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" + integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== + +node-forge@^1.3.2: + version "1.3.3" + resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-1.3.3.tgz#0ad80f6333b3a0045e827ac20b7f735f93716751" + integrity sha512-rLvcdSyRCyouf6jcOIPe/BgwG/d7hKjzMKOas33/pHEr6gbq18IK9zV7DiPvzsz0oBJPme6qr6H6kGZuI9/DZg== + 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== +node-releases@^2.0.27: + version "2.0.27" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.27.tgz#eedca519205cf20f650f61d56b070db111231e4e" + integrity sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA== normalize-path@^3.0.0: version "3.0.0" @@ -2669,6 +3152,11 @@ object-inspect@^1.13.3: resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.4.tgz#8375265e21bc20d0fa582c22e1b13485d6e00213" integrity sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew== +on-exit-leak-free@^2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz#fed195c9ebddb7d9e4c3842f93f281ac8dadd3b8" + integrity sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA== + on-finished@^2.4.1: version "2.4.1" resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" @@ -2676,7 +3164,7 @@ on-finished@^2.4.1: dependencies: ee-first "1.1.1" -once@^1.3.0, once@^1.4.0: +once@^1.3.0, once@^1.3.1, 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== @@ -2702,6 +3190,11 @@ optionator@^0.9.3: type-check "^0.4.0" word-wrap "^1.2.5" +os-tmpdir@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g== + p-all@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/p-all/-/p-all-3.0.0.tgz#077c023c37e75e760193badab2bad3ccd5782bfb" @@ -2797,9 +3290,9 @@ path-parse@^1.0.7: 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== + version "8.3.0" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-8.3.0.tgz#aa818a6981f99321003a08987d3cec9c3474cd1f" + integrity sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA== picocolors@^1.1.1: version "1.1.1" @@ -2811,15 +3304,73 @@ picomatch@^2.0.4, picomatch@^2.2.3, picomatch@^2.3.1: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== +pino-abstract-transport@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/pino-abstract-transport/-/pino-abstract-transport-3.0.0.tgz#b21e5f33a297e8c4c915c62b3ce5dd4a87a52c23" + integrity sha512-wlfUczU+n7Hy/Ha5j9a/gZNy7We5+cXp8YL+X+PG8S0KXxw7n/JXA3c46Y0zQznIJ83URJiwy7Lh56WLokNuxg== + dependencies: + split2 "^4.0.0" + +pino-http@^11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/pino-http/-/pino-http-11.0.0.tgz#ebadef4694fc59aadab9be7e5939aea625b4615f" + integrity sha512-wqg5XIAGRRIWtTk8qPGxkbrfiwEWz1lgedVLvhLALudKXvg1/L2lTFgTGPJ4Z2e3qcRmxoFxDuSdMdMGNM6I1g== + dependencies: + get-caller-file "^2.0.5" + pino "^10.0.0" + pino-std-serializers "^7.0.0" + process-warning "^5.0.0" + +pino-pretty@^13.1.3: + version "13.1.3" + resolved "https://registry.yarnpkg.com/pino-pretty/-/pino-pretty-13.1.3.tgz#2274cccda925dd355c104079a5029f6598d0381b" + integrity sha512-ttXRkkOz6WWC95KeY9+xxWL6AtImwbyMHrL1mSwqwW9u+vLp/WIElvHvCSDg0xO/Dzrggz1zv3rN5ovTRVowKg== + dependencies: + colorette "^2.0.7" + dateformat "^4.6.3" + fast-copy "^4.0.0" + fast-safe-stringify "^2.1.1" + help-me "^5.0.0" + joycon "^3.1.1" + minimist "^1.2.6" + on-exit-leak-free "^2.1.0" + pino-abstract-transport "^3.0.0" + pump "^3.0.0" + secure-json-parse "^4.0.0" + sonic-boom "^4.0.1" + strip-json-comments "^5.0.2" + +pino-std-serializers@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/pino-std-serializers/-/pino-std-serializers-7.1.0.tgz#a7b0cd65225f29e92540e7853bd73b07479893fc" + integrity sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw== + +pino@^10.0.0, pino@^10.3.1: + version "10.3.1" + resolved "https://registry.yarnpkg.com/pino/-/pino-10.3.1.tgz#6552c8f8d8481844c9e452e7bf0be90bff1939ce" + integrity sha512-r34yH/GlQpKZbU1BvFFqOjhISRo1MNx1tWYsYvmj6KIRHSPMT2+yHOEb1SG6NMvRoHRF0a07kCOox/9yakl1vg== + dependencies: + "@pinojs/redact" "^0.4.0" + atomic-sleep "^1.0.0" + on-exit-leak-free "^2.1.0" + pino-abstract-transport "^3.0.0" + pino-std-serializers "^7.0.0" + process-warning "^5.0.0" + quick-format-unescaped "^4.0.3" + real-require "^0.2.0" + safe-stable-stringify "^2.3.1" + sonic-boom "^4.0.1" + thread-stream "^4.0.0" + 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== + version "5.0.1" + resolved "https://registry.yarnpkg.com/pkce-challenge/-/pkce-challenge-5.0.1.tgz#3b4446865b17b1745e9ace2016a31f48ddf6230d" + integrity sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ== pkg-dir@^4.2.0: version "4.2.0" @@ -2833,17 +3384,22 @@ prelude-ls@^1.2.1: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== -prettier-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== +prettier-linter-helpers@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.1.tgz#6a31f88a4bad6c7adda253de12ba4edaea80ebcd" + integrity sha512-SxToR7P8Y2lWmv/kTzVLC1t/GDI2WGjMwNhLLE9qtH8Q13C+aEmuRlzDst4Up4s0Wc8sF2M+J57iB3cMLqftfg== 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== + version "3.7.4" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.7.4.tgz#d2f8335d4b1cec47e1c8098645411b0c9dff9c0f" + integrity sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA== + +pretty-bytes@^5.6.0: + version "5.6.0" + resolved "https://registry.yarnpkg.com/pretty-bytes/-/pretty-bytes-5.6.0.tgz#356256f643804773c82f64723fe78c92c62beaeb" + integrity sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg== pretty-format@^29.0.0, pretty-format@^29.7.0: version "29.7.0" @@ -2854,6 +3410,11 @@ pretty-format@^29.0.0, pretty-format@^29.7.0: ansi-styles "^5.0.0" react-is "^18.0.0" +process-warning@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/process-warning/-/process-warning-5.0.0.tgz#566e0bf79d1dff30a72d8bbbe9e8ecefe8d378d7" + integrity sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA== + prompts@^2.0.1: version "2.4.2" resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" @@ -2870,6 +3431,14 @@ proxy-addr@^2.0.7: forwarded "0.2.0" ipaddr.js "1.9.1" +pump@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.4.tgz#1f313430527fa8b905622ebd22fe1444e757ab3c" + integrity sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + punycode@^2.1.0: version "2.3.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" @@ -2880,10 +3449,10 @@ pure-rand@^6.0.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== +qs@^6.14.0, qs@^6.14.1: + version "6.14.1" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.14.1.tgz#a41d85b9d3902f31d27861790506294881871159" + integrity sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ== dependencies: side-channel "^1.1.0" @@ -2892,20 +3461,25 @@ queue-microtask@^1.2.2: resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== +quick-format-unescaped@^4.0.3: + version "4.0.4" + resolved "https://registry.yarnpkg.com/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz#93ef6dd8d3453cbc7970dd614fad4c5954d6b5a7" + integrity sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg== + 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== +raw-body@^3.0.0, raw-body@^3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-3.0.2.tgz#3e3ada5ae5568f9095d84376fd3a49b8fb000a51" + integrity sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA== dependencies: - bytes "3.1.2" - http-errors "2.0.0" - iconv-lite "0.6.3" - unpipe "1.0.0" + bytes "~3.1.2" + http-errors "~2.0.1" + iconv-lite "~0.7.0" + unpipe "~1.0.0" react-is@^18.0.0: version "18.3.1" @@ -2921,11 +3495,21 @@ readable-stream@^3.4.0: string_decoder "^1.1.1" util-deprecate "^1.0.1" +real-require@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/real-require/-/real-require-0.2.0.tgz#209632dea1810be2ae063a6ac084fee7e33fba78" + integrity sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg== + 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== +require-from-string@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== + resolve-cwd@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" @@ -2949,11 +3533,11 @@ resolve.exports@^2.0.0: 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== + version "1.22.11" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.11.tgz#aad857ce1ffb8bfa9b0b1ac29f1156383f68c262" + integrity sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ== dependencies: - is-core-module "^2.16.0" + is-core-module "^2.16.1" path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" @@ -2962,13 +3546,6 @@ reusify@^1.0.4: 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" @@ -2987,54 +3564,64 @@ run-parallel@^1.1.9: dependencies: queue-microtask "^1.2.2" -safe-buffer@5.2.1, safe-buffer@~5.2.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": +safe-stable-stringify@^2.3.1: + version "2.5.0" + resolved "https://registry.yarnpkg.com/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz#4ca2f8e385f2831c432a719b108a3bf7af42a1dd" + integrity sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA== + +"safer-buffer@>= 2.1.2 < 3", "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== +secure-json-parse@^4.0.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/secure-json-parse/-/secure-json-parse-4.1.0.tgz#4f1ab41c67a13497ea1b9131bb4183a22865477c" + integrity sha512-l4KnYfEyqYJxDwlNVyRfO2E4NTHfMKAWdUuA8J0yve2Dz/E/PdBepY03RvyJpssIpRFwJoCD55wA+mEDs6ByWA== + 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== +semver@^7.5.3, semver@^7.5.4, semver@^7.6.0, semver@^7.7.3: + version "7.7.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.3.tgz#4b5f4143d007633a8dc671cd0a6ef9147b8bb946" + integrity sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q== 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== + version "1.2.1" + resolved "https://registry.yarnpkg.com/send/-/send-1.2.1.tgz#9eab743b874f3550f40a26867bf286ad60d3f3ed" + integrity sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ== dependencies: - debug "^4.3.5" + debug "^4.4.3" 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" + http-errors "^2.0.1" + mime-types "^3.0.2" ms "^2.1.3" on-finished "^2.4.1" range-parser "^1.2.1" - statuses "^2.0.1" + statuses "^2.0.2" 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== + version "2.2.1" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-2.2.1.tgz#7f186a4a4e5f5b663ad7a4294ff1bf37cf0e98a9" + integrity sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw== dependencies: encodeurl "^2.0.0" escape-html "^1.0.3" parseurl "^1.3.3" send "^1.2.0" -setprototypeof@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== @@ -3096,6 +3683,11 @@ signal-exit@^3.0.3, signal-exit@^3.0.7: resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== +signal-exit@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" + integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== + sisteransi@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" @@ -3106,6 +3698,13 @@ slash@^3.0.0: resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== +sonic-boom@^4.0.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/sonic-boom/-/sonic-boom-4.2.1.tgz#28598250df4899c0ac572d7e2f0460690ba6a030" + integrity sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q== + dependencies: + atomic-sleep "^1.0.0" + 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" @@ -3119,6 +3718,11 @@ source-map@^0.6.0, source-map@^0.6.1: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== +split2@^4.0.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/split2/-/split2-4.2.0.tgz#c9c5920904d148bab0b9f67145f245a86aadbfa4" + integrity sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg== + sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" @@ -3131,10 +3735,10 @@ stack-utils@^2.0.3: 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== +statuses@^2.0.1, statuses@^2.0.2, statuses@~2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.2.tgz#8f75eecef765b5e1cfcdc080da59409ed424e382" + integrity sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw== string-length@^4.0.1: version "4.0.2" @@ -3194,6 +3798,11 @@ strip-json-comments@^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== +strip-json-comments@^5.0.2: + version "5.0.3" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-5.0.3.tgz#b7304249dd402ee67fd518ada993ab3593458bcf" + integrity sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw== + superstruct@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/superstruct/-/superstruct-1.0.4.tgz#0adb99a7578bd2f1c526220da6571b2d485d91ca" @@ -3218,13 +3827,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.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== +synckit@^0.11.12: + version "0.11.12" + resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.11.12.tgz#abe74124264fbc00a48011b0d98bdc1cffb64a7b" + integrity sha512-Bh7QjT8/SuKUIfObSXNHNSK6WHo6J1tHCqJsuaFDP7gP0fkzSfTxI8y85JrppZ0h8l0maIgc2tfuZQ6/t3GtnQ== dependencies: - "@pkgr/core" "^0.2.3" - tslib "^2.8.1" + "@pkgr/core" "^0.2.9" test-exclude@^6.0.0: version "6.0.0" @@ -3235,10 +3843,19 @@ test-exclude@^6.0.0: glob "^7.1.4" minimatch "^3.0.4" -text-table@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" - integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== +thread-stream@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/thread-stream/-/thread-stream-4.0.0.tgz#732f007c24da7084f729d6e3a7e3f5934a7380b7" + integrity sha512-4iMVL6HAINXWf1ZKZjIPcz5wYaOdPhtO8ATvZ+Xqp3BTdaqtAwQkNmKORqcIo5YkQqGXq5cwfswDwMqqQNrpJA== + dependencies: + real-require "^0.2.0" + +tmp@^0.0.33: + version "0.0.33" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== + dependencies: + os-tmpdir "~1.0.2" tmpl@1.0.5: version "1.0.5" @@ -3252,30 +3869,29 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" -toidentifier@1.0.1: +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== + version "2.4.0" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-2.4.0.tgz#2690579f96d2790253bdcf1ca35d569ad78f9ad8" + integrity sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA== 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== + version "29.4.6" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-29.4.6.tgz#51cb7c133f227396818b71297ad7409bb77106e9" + integrity sha512-fSpWtOO/1AjSNQguk43hb/JCo16oJDnMJf3CdEGNkqsEX3t0KX96xvyX1D7PfLCpVoKu4MfVrqUkFyblYoY4lA== dependencies: bs-logger "^0.2.6" - ejs "^3.1.10" fast-json-stable-stringify "^2.1.0" - jest-util "^29.0.0" + handlebars "^4.7.8" json5 "^2.2.3" lodash.memoize "^4.1.2" make-error "^1.3.6" - semver "^7.7.1" - type-fest "^4.39.1" + semver "^7.7.3" + type-fest "^4.41.0" yargs-parser "^21.1.1" ts-morph@^19.0.0: @@ -3305,9 +3921,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.11/tsc-multi.tgz": + version "1.1.11" + resolved "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.11/tsc-multi.tgz#010247051be13b55abdc98f787c017285149f4f2" dependencies: debug "^4.3.7" fast-glob "^3.3.2" @@ -3346,22 +3962,17 @@ type-detect@4.0.8: resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== -type-fest@^0.20.2: - version "0.20.2" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" - integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== - type-fest@^0.21.3: version "0.21.3" resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== -type-fest@^4.39.1: +type-fest@^4.41.0: 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: +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== @@ -3375,20 +3986,35 @@ typescript@5.8.3: resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.8.3.tgz#92f8a3e5e3cf497356f4178c34cd65a7f5e8440e" integrity sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ== +uglify-js@^3.1.4: + version "3.19.3" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.19.3.tgz#82315e9bbc6f2b25888858acd1fff8441035b77f" + integrity sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ== + 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: +undici-types@~7.16.0: + version "7.16.0" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-7.16.0.tgz#ffccdff36aea4884cbfce9a750a0580224f58a46" + integrity sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw== + +universalify@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.1.tgz#168efc2180964e6386d061e094df61afe239b18d" + integrity sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw== + +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== +update-browserslist-db@^1.2.0: + version "1.2.3" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz#64d76db58713136acbeb4c49114366cc6cc2e80d" + integrity sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w== dependencies: escalade "^3.2.0" picocolors "^1.1.1" @@ -3443,6 +4069,20 @@ word-wrap@^1.2.5: resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== +wordwrap@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + integrity sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q== + +wrap-ansi@^6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" + integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.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" @@ -3503,12 +4143,27 @@ yocto-queue@^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== +yoctocolors-cjs@^2.1.2: + version "2.1.3" + resolved "https://registry.yarnpkg.com/yoctocolors-cjs/-/yoctocolors-cjs-2.1.3.tgz#7e4964ea8ec422b7a40ac917d3a344cfd2304baa" + integrity sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw== -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== +zod-to-json-schema@^3.24.5, zod-to-json-schema@^3.24.6, zod-to-json-schema@^3.25.1: + version "3.25.1" + resolved "https://registry.yarnpkg.com/zod-to-json-schema/-/zod-to-json-schema-3.25.1.tgz#7f24962101a439ddade2bf1aeab3c3bfec7d84ba" + integrity sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA== + +zod-validation-error@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/zod-validation-error/-/zod-validation-error-4.0.2.tgz#bc605eba49ce0fcd598c127fee1c236be3f22918" + integrity sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ== + +"zod@^3.25 || ^4.0": + version "4.3.5" + resolved "https://registry.yarnpkg.com/zod/-/zod-4.3.5.tgz#aeb269a6f9fc259b1212c348c7c5432aaa474d2a" + integrity sha512-k7Nwx6vuWx1IJ9Bjuf4Zt1PEllcwe7cls3VNzm4CQ1/hgtFUK2bRNG3rvnpPUhFjmqJKAKtjV576KnUkHocg/g== + +zod@^3.25.20, zod@^3.25.67: + version "3.25.76" + resolved "https://registry.yarnpkg.com/zod/-/zod-3.25.76.tgz#26841c3f6fd22a6a2760e7ccb719179768471e34" + integrity sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ== diff --git a/release-please-config.json b/release-please-config.json new file mode 100644 index 00000000..9b042792 --- /dev/null +++ b/release-please-config.json @@ -0,0 +1,78 @@ +{ + "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", + "packages/mcp-server/yarn.lock", + { + "type": "json", + "path": "packages/mcp-server/package.json", + "jsonpath": "$.version" + }, + { + "type": "json", + "path": "packages/mcp-server/manifest.json", + "jsonpath": "$.version" + } + ] +} diff --git a/scripts/bootstrap b/scripts/bootstrap index 0af58e25..2e315f53 100755 --- a/scripts/bootstrap +++ b/scripts/bootstrap @@ -4,10 +4,18 @@ set -e cd "$(dirname "$0")/.." -if [ -f "Brewfile" ] && [ "$(uname -s)" = "Darwin" ] && [ "$SKIP_BREW" != "1" ]; then +if [ -f "Brewfile" ] && [ "$(uname -s)" = "Darwin" ] && [ "${SKIP_BREW:-}" != "1" ] && [ -t 0 ]; then brew bundle check >/dev/null 2>&1 || { - echo "==> Installing Homebrew dependencies…" - brew bundle + echo -n "==> Install Homebrew dependencies? (y/N): " + read -r response + case "$response" in + [yY][eE][sS]|[yY]) + brew bundle + ;; + *) + ;; + esac + echo } fi @@ -15,4 +23,4 @@ echo "==> Installing Node dependencies…" PACKAGE_MANAGER=$(command -v yarn >/dev/null 2>&1 && echo "yarn" || echo "npm") -$PACKAGE_MANAGER install +$PACKAGE_MANAGER install "$@" diff --git a/scripts/build b/scripts/build index 84506808..43cb20e1 100755 --- a/scripts/build +++ b/scripts/build @@ -8,7 +8,7 @@ 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 `"beagle/resources/foo"` works +# This way importing from `"@corgi-tech/beagle/resources/foo"` works # even with `"moduleResolution": "node"` rm -rf dist; mkdir dist @@ -42,8 +42,8 @@ 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("beagle")') -(cd dist && node -e 'import("beagle")' --input-type=module) +(cd dist && node -e 'require("@corgi-tech/beagle")') +(cd dist && node -e 'import("@corgi-tech/beagle")' --input-type=module) if [ -e ./scripts/build-deno ] then @@ -52,6 +52,6 @@ fi # build all sub-packages for dir in packages/*; do if [ -d "$dir" ]; then - (cd "$dir" && yarn install && yarn build) + (cd "$dir" && yarn install --pure-lockfile && yarn build) fi done diff --git a/scripts/fast-format b/scripts/fast-format new file mode 100755 index 00000000..f1873aef --- /dev/null +++ b/scripts/fast-format @@ -0,0 +1,37 @@ +#!/usr/bin/env bash + +set -euo pipefail + +echo "Script started with $# arguments" +echo "Arguments: $*" +echo "Script location: $(dirname "$0")" + +cd "$(dirname "$0")/.." +echo "Changed to directory: $(pwd)" + +if [ $# -eq 0 ]; then + echo "Usage: $0 [additional-formatter-args...]" + echo "The file should contain one file path per line" + exit 1 +fi + +FILE_LIST="$1" + +echo "Looking for file: $FILE_LIST" + +if [ ! -f "$FILE_LIST" ]; then + echo "Error: File '$FILE_LIST' not found" + exit 1 +fi + +echo "==> Running eslint --fix" +ESLINT_FILES="$(grep '\.ts$' "$FILE_LIST" || true)" +if ! [ -z "$ESLINT_FILES" ]; then + echo "$ESLINT_FILES" | xargs ./node_modules/.bin/eslint --cache --fix +fi + +echo "==> Running prettier --write" +if ! [ -z "$FILE_LIST" ]; then + cat "$FILE_LIST" | xargs ./node_modules/.bin/prettier \ + --write --cache --cache-strategy metadata --no-error-on-unmatched-pattern --ignore-unknown +fi diff --git a/scripts/format b/scripts/format index 7a756401..b1b2c17a 100755 --- a/scripts/format +++ b/scripts/format @@ -8,5 +8,4 @@ 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' +./node_modules/.bin/prettier --write --cache --cache-strategy metadata . diff --git a/scripts/lint b/scripts/lint index 3ffb78a6..1f532548 100755 --- a/scripts/lint +++ b/scripts/lint @@ -4,6 +4,9 @@ set -e cd "$(dirname "$0")/.." +echo "==> Running prettier --check" +./node_modules/.bin/prettier --check . + echo "==> Running eslint" ./node_modules/.bin/eslint . diff --git a/scripts/mock b/scripts/mock deleted file mode 100755 index d2814ae6..00000000 --- a/scripts/mock +++ /dev/null @@ -1,41 +0,0 @@ -#!/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 index 2049e31b..548da9bb 100755 --- a/scripts/test +++ b/scripts/test @@ -4,53 +4,7 @@ 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/postprocess-files.cjs b/scripts/utils/postprocess-files.cjs index deae575e..a8cdeb7c 100644 --- a/scripts/utils/postprocess-files.cjs +++ b/scripts/utils/postprocess-files.cjs @@ -23,12 +23,19 @@ async function postprocess() { // 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( + let transformed = code.replace( /^ *\/\/\/ * ' '.repeat(match.length - 1) + '\n', ); + // TypeScript's declaration emitter collapses /** @ts-ignore */ onto the same + // line as the type declaration, which doesn't work. So we convert to // @ts-ignore + // on its own line to properly suppresses errors. + if (file.endsWith('.d.ts') || file.endsWith('.d.mts') || file.endsWith('.d.cts')) { + transformed = transformed.replace(/\/\*\* @ts-ignore\b[^*]*\*\/ /gm, '// @ts-ignore\n'); + } + if (transformed !== code) { console.error(`wrote ${path.relative(process.cwd(), file)}`); await fs.promises.writeFile(file, transformed, 'utf8'); diff --git a/scripts/utils/upload-artifact.sh b/scripts/utils/upload-artifact.sh index 84276dec..09791ec8 100755 --- a/scripts/utils/upload-artifact.sh +++ b/scripts/utils/upload-artifact.sh @@ -12,9 +12,11 @@ if [[ "$SIGNED_URL" == "null" ]]; then exit 1 fi -UPLOAD_RESPONSE=$(tar -cz dist | curl -v -X PUT \ +TARBALL=$(cd dist && npm pack --silent) + +UPLOAD_RESPONSE=$(curl -v -X PUT \ -H "Content-Type: application/gzip" \ - --data-binary @- "$SIGNED_URL" 2>&1) + --data-binary "@dist/$TARBALL" "$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" diff --git a/src/client.ts b/src/client.ts index 9b6ee2ea..e269a36e 100644 --- a/src/client.ts +++ b/src/client.ts @@ -11,6 +11,7 @@ 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 { stringifyQuery } from './internal/utils/query'; import { VERSION } from './version'; import * as Errors from './core/error'; import * as Pagination from './core/pagination'; @@ -31,34 +32,42 @@ import { APIPromise } from './core/api-promise'; import { Enrollment, EnrollmentCreateParams, + EnrollmentCreateResponse, EnrollmentListParams, + EnrollmentListResponse, + EnrollmentRetrieveResponse, Enrollments, - EnrollmentsEnrollmentsPagination, } from './resources/enrollments'; import { InsuranceVerification, InsuranceVerificationVerifyParams, InsuranceVerificationVerifyResponse, } from './resources/insurance-verification'; -import { Plan, PlanListResponse, Plans } from './resources/plans'; +import { Plan, PlanListResponse, PlanRetrieveResponse, Plans } from './resources/plans'; import { Pagination as PropertyManagersAPIPagination, PropertyManager, PropertyManagerCreateParams, + PropertyManagerCreateResponse, PropertyManagerListParams, + PropertyManagerListResponse, + PropertyManagerRetrieveResponse, PropertyManagerUpdateParams, + PropertyManagerUpdateResponse, PropertyManagers, - PropertyManagersPropertyManagersPagination, } from './resources/property-managers'; import { Address, Contact, Tenant, TenantCreateParams, + TenantCreateResponse, TenantListParams, + TenantListResponse, + TenantRetrieveResponse, TenantUpdateParams, + TenantUpdateResponse, Tenants, - TenantsTenantsPagination, } from './resources/tenants'; import { Webhook } from './resources/webhook/webhook'; import { type Fetch } from './internal/builtin-types'; @@ -173,7 +182,7 @@ export class Beagle { baseURL: string; maxRetries: number; timeout: number; - logger: Logger | undefined; + logger: Logger; logLevel: LogLevel | undefined; fetchOptions: MergedRequestInit | undefined; @@ -234,6 +243,18 @@ export class Beagle { this.fetch = options.fetch ?? Shims.getDefaultFetch(); this.#encoder = Opts.FallbackEncoder; + const customHeadersEnv = readEnv('BEAGLE_CUSTOM_HEADERS'); + if (customHeadersEnv) { + const parsed: Record = {}; + for (const line of customHeadersEnv.split('\n')) { + const colon = line.indexOf(':'); + if (colon >= 0) { + parsed[line.substring(0, colon).trim()] = line.substring(colon + 1).trim(); + } + } + options.defaultHeaders = { ...parsed, ...options.defaultHeaders }; + } + this._options = options; this.apiKey = apiKey; @@ -243,7 +264,7 @@ export class Beagle { * 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, environment: options.environment ? options.environment : undefined, baseURL: options.environment ? undefined : this.baseURL, @@ -256,6 +277,7 @@ export class Beagle { apiKey: this.apiKey, ...options, }); + return client; } /** @@ -273,28 +295,15 @@ export class Beagle { return; } - protected authHeaders(opts: FinalRequestOptions): NullableHeaders | undefined { + protected async authHeaders(opts: FinalRequestOptions): Promise { 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.BeagleError( - `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('&'); + protected stringifyQuery(query: object | Record): string { + return stringifyQuery(query); } private getUserAgent(): string { @@ -326,12 +335,13 @@ export class Beagle { : new URL(baseURL + (baseURL.endsWith('/') && path.startsWith('/') ? path.slice(1) : path)); const defaultQuery = this.defaultQuery(); - if (!isEmptyObj(defaultQuery)) { - query = { ...defaultQuery, ...query }; + const pathQuery = Object.fromEntries(url.searchParams); + if (!isEmptyObj(defaultQuery) || !isEmptyObj(pathQuery)) { + query = { ...pathQuery, ...defaultQuery, ...query }; } if (typeof query === 'object' && query && !Array.isArray(query)) { - url.search = this.stringifyQuery(query as Record); + url.search = this.stringifyQuery(query); } return url.toString(); @@ -405,7 +415,9 @@ export class Beagle { 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 }); @@ -433,7 +445,7 @@ export class Beagle { const response = await this.fetchWithTimeout(url, req, timeout, controller).catch(castToError); const headersTime = Date.now(); - if (response instanceof Error) { + if (response instanceof globalThis.Error) { const retryMessage = `retrying, ${retriesRemaining} attempts remaining`; if (options.signal?.aborted) { throw new Errors.APIUserAbortError(); @@ -483,7 +495,7 @@ export class Beagle { } 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`; @@ -513,7 +525,7 @@ export class Beagle { loggerFor(this).info(`${responseInfo} - ${retryMessage}`); const errText = await response.text().catch((err: any) => castToError(err).message); - const errJSON = safeJSON(errText); + const errJSON = safeJSON(errText) as any; const errMessage = errJSON ? undefined : errText; loggerFor(this).debug( @@ -550,9 +562,14 @@ export class Beagle { getAPIList = Pagination.AbstractPage>( path: string, Page: new (...args: any[]) => PageClass, - opts?: RequestOptions, + opts?: PromiseOrValue, ): Pagination.PagePromise { - return this.requestAPIList(Page, { method: 'get', path, ...opts }); + return this.requestAPIList( + Page, + opts && 'then' in opts ? + opts.then((opts) => ({ method: 'get', path, ...opts })) + : { method: 'get', path, ...opts }, + ); } requestAPIList< @@ -560,7 +577,7 @@ export class Beagle { PageClass extends Pagination.AbstractPage = Pagination.AbstractPage, >( Page: new (...args: ConstructorParameters) => PageClass, - options: FinalRequestOptions, + options: PromiseOrValue, ): Pagination.PagePromise { const request = this.makeRequest(options, null, undefined); return new Pagination.PagePromise(this as any as Beagle, request, Page); @@ -573,9 +590,10 @@ export class Beagle { controller: AbortController, ): Promise { const { signal, method, ...options } = init || {}; - if (signal) signal.addEventListener('abort', () => controller.abort()); + const abort = this._makeAbort(controller); + if (signal) signal.addEventListener('abort', abort, { once: true }); - const timeout = setTimeout(() => controller.abort(), ms); + const timeout = setTimeout(abort, ms); const isReadableBody = ((globalThis as any).ReadableStream && options.body instanceof (globalThis as any).ReadableStream) || @@ -601,7 +619,7 @@ export class Beagle { } } - 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'); @@ -652,9 +670,9 @@ export class Beagle { } } - // 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)) { + // If the API asks us to wait a certain amount of time, just do what it + // says, but otherwise calculate a default + if (timeoutMillis === undefined) { const maxRetries = options.maxRetries ?? this.maxRetries; timeoutMillis = this.calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries); } @@ -678,10 +696,10 @@ export class Beagle { 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; @@ -689,7 +707,7 @@ export class Beagle { 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, @@ -705,7 +723,7 @@ export class Beagle { return { req, url, timeout: options.timeout }; } - private buildHeaders({ + private async buildHeaders({ options, method, bodyHeaders, @@ -715,7 +733,7 @@ export class Beagle { method: HTTPMethod; bodyHeaders: HeadersLike; retryCount: number; - }): Headers { + }): Promise { let idempotencyHeaders: HeadersLike = {}; if (this.idempotencyHeader && method !== 'get') { if (!options.idempotencyKey) options.idempotencyKey = this.defaultIdempotencyKey(); @@ -731,7 +749,7 @@ export class Beagle { ...(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, @@ -742,11 +760,25 @@ export class Beagle { return headers.values; } - private buildBody({ options: { body, headers: rawHeaders } }: { options: FinalRequestOptions }): { + private _makeAbort(controller: AbortController) { + // note: we can't just inline this method inside `fetchWithTimeout()` because then the closure + // would capture all request options, and cause a memory leak. + return () => controller.abort(); + } + + private buildBody({ options }: { options: FinalRequestOptions }): { bodyHeaders: HeadersLike; body: BodyInit | undefined; } { + const { body, headers: rawHeaders } = options; if (!body) { + // A resource method always passes a `body` key when its operation defines a + // request body, even if the caller omitted an optional body param. Keep the + // content-type for those, and only elide it for operations with no body at + // all (e.g. GET/DELETE). + if (body == null && 'body' in options) { + return this.#encoder({ body, headers: buildHeaders([rawHeaders]) }); + } return { bodyHeaders: undefined, body: undefined }; } const headers = buildHeaders([rawHeaders]); @@ -759,7 +791,7 @@ export class Beagle { // 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` @@ -774,6 +806,14 @@ export class Beagle { (Symbol.iterator in body && 'next' in body && typeof body.next === 'function')) ) { return { bodyHeaders: undefined, body: Shims.ReadableStreamFrom(body as AsyncIterable) }; + } else if ( + typeof body === 'object' && + headers.values.get('content-type') === 'application/x-www-form-urlencoded' + ) { + return { + bodyHeaders: { 'content-type': 'application/x-www-form-urlencoded' }, + body: this.stringifyQuery(body), + }; } else { return this.#encoder({ body, headers }); } @@ -798,19 +838,36 @@ export class Beagle { static toFile = Uploads.toFile; + /** + * Retrieve a list of all plans or look up details by plan code. Each plan defines its name, description, rate, and any coverage values. + */ plans: API.Plans = new API.Plans(this); + /** + * Track and update your property managers. Create, list, retrieve, update, or delete property manager profiles. Each profile aggregates addresses and contact channels for billing, legal, and support. + */ propertyManagers: API.PropertyManagers = new API.PropertyManagers(this); + /** + * Maintain your tenant directory and their primary contact and address. You can create, update, retrieve, list, or delete tenant records. Listings support pagination and filtering by property manager. + */ tenants: API.Tenants = new API.Tenants(this); + /** + * Handle the connections of tenants to plans over time. Create, list, retrieve, or lapse an enrollment records. Enrollments record the chosen plan, effective date, and optional notes. + */ enrollments: API.Enrollments = new API.Enrollments(this); + /** + * Trigger insurance document parsing and verifications on demand. This is currently under development please reach out for support integrating. + */ insuranceVerification: API.InsuranceVerification = new API.InsuranceVerification(this); webhook: API.Webhook = new API.Webhook(this); } + Beagle.Plans = Plans; Beagle.PropertyManagers = PropertyManagers; Beagle.Tenants = Tenants; Beagle.Enrollments = Enrollments; Beagle.InsuranceVerification = InsuranceVerification; Beagle.Webhook = Webhook; + export declare namespace Beagle { export type RequestOptions = Opts.RequestOptions; @@ -838,13 +895,21 @@ export declare namespace Beagle { type WebhookEndpointsPaginationResponse as WebhookEndpointsPaginationResponse, }; - export { Plans as Plans, type Plan as Plan, type PlanListResponse as PlanListResponse }; + export { + Plans as Plans, + type Plan as Plan, + type PlanRetrieveResponse as PlanRetrieveResponse, + type PlanListResponse as PlanListResponse, + }; export { PropertyManagers as PropertyManagers, type PropertyManagersAPIPagination as Pagination, type PropertyManager as PropertyManager, - type PropertyManagersPropertyManagersPagination as PropertyManagersPropertyManagersPagination, + type PropertyManagerCreateResponse as PropertyManagerCreateResponse, + type PropertyManagerRetrieveResponse as PropertyManagerRetrieveResponse, + type PropertyManagerUpdateResponse as PropertyManagerUpdateResponse, + type PropertyManagerListResponse as PropertyManagerListResponse, type PropertyManagerCreateParams as PropertyManagerCreateParams, type PropertyManagerUpdateParams as PropertyManagerUpdateParams, type PropertyManagerListParams as PropertyManagerListParams, @@ -855,7 +920,10 @@ export declare namespace Beagle { type Address as Address, type Contact as Contact, type Tenant as Tenant, - type TenantsTenantsPagination as TenantsTenantsPagination, + type TenantCreateResponse as TenantCreateResponse, + type TenantRetrieveResponse as TenantRetrieveResponse, + type TenantUpdateResponse as TenantUpdateResponse, + type TenantListResponse as TenantListResponse, type TenantCreateParams as TenantCreateParams, type TenantUpdateParams as TenantUpdateParams, type TenantListParams as TenantListParams, @@ -864,7 +932,9 @@ export declare namespace Beagle { export { Enrollments as Enrollments, type Enrollment as Enrollment, - type EnrollmentsEnrollmentsPagination as EnrollmentsEnrollmentsPagination, + type EnrollmentCreateResponse as EnrollmentCreateResponse, + type EnrollmentRetrieveResponse as EnrollmentRetrieveResponse, + type EnrollmentListResponse as EnrollmentListResponse, type EnrollmentCreateParams as EnrollmentCreateParams, type EnrollmentListParams as EnrollmentListParams, }; diff --git a/src/core/pagination.ts b/src/core/pagination.ts index d23529e0..f9fe8fa3 100644 --- a/src/core/pagination.ts +++ b/src/core/pagination.ts @@ -164,9 +164,9 @@ export class PropertyManagersPagination } nextPageRequestOptions(): PageRequestOptions | null { - const currentPage = this.pagination?.page; + const currentPage = this.pagination?.page ?? 1; - if (currentPage >= this.pagination?.pages) { + if (this.pagination.pages != null && currentPage >= this.pagination.pages) { return null; } @@ -234,9 +234,9 @@ export class TenantsPagination extends AbstractPage implements Tenan } nextPageRequestOptions(): PageRequestOptions | null { - const currentPage = this.pagination?.page; + const currentPage = this.pagination?.page ?? 1; - if (currentPage >= this.pagination?.pages) { + if (this.pagination.pages != null && currentPage >= this.pagination.pages) { return null; } @@ -307,9 +307,9 @@ export class EnrollmentsPagination } nextPageRequestOptions(): PageRequestOptions | null { - const currentPage = this.pagination?.page; + const currentPage = this.pagination?.page ?? 1; - if (currentPage >= this.pagination?.pages) { + if (this.pagination.pages != null && currentPage >= this.pagination.pages) { return null; } @@ -380,9 +380,9 @@ export class WebhookEndpointsPagination } nextPageRequestOptions(): PageRequestOptions | null { - const currentPage = this.pagination?.page; + const currentPage = this.pagination?.page ?? 1; - if (currentPage >= this.pagination?.pages) { + if (this.pagination.pages != null && currentPage >= this.pagination.pages) { return null; } diff --git a/src/internal/parse.ts b/src/internal/parse.ts index 9484cb0a..0da1dab4 100644 --- a/src/internal/parse.ts +++ b/src/internal/parse.ts @@ -29,6 +29,12 @@ export async function defaultParseResponse(client: Beagle, props: APIResponse const mediaType = contentType?.split(';')[0]?.trim(); const isJSON = mediaType?.includes('application/json') || mediaType?.endsWith('+json'); if (isJSON) { + const contentLength = response.headers.get('content-length'); + if (contentLength === '0') { + // if there is no content we can't do anything + return undefined as T; + } + const json = await response.json(); return json as T; } diff --git a/src/internal/to-file.ts b/src/internal/to-file.ts index 245e8493..30eada32 100644 --- a/src/internal/to-file.ts +++ b/src/internal/to-file.ts @@ -73,7 +73,7 @@ export type ToFileInput = /** * 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 value the raw content of the file. Can be an {@link Uploadable}, BlobLikePart, or AsyncIterable of BlobLikeParts * @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 diff --git a/src/internal/types.ts b/src/internal/types.ts index b668dfc0..a050513a 100644 --- a/src/internal/types.ts +++ b/src/internal/types.ts @@ -40,7 +40,6 @@ type OverloadedParameters = : 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 @@ -63,19 +62,18 @@ type OverloadedParameters = * * [1]: https://www.typescriptlang.org/tsconfig/#typeAcquisition */ -/** @ts-ignore For users with \@types/node */ +/** @ts-ignore For users with \@types/node */ /* prettier-ignore */ type UndiciTypesRequestInit = NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny; -/** @ts-ignore For users with undici */ +/** @ts-ignore For users with undici */ /* prettier-ignore */ type UndiciRequestInit = NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny; -/** @ts-ignore For users with \@types/bun */ +/** @ts-ignore For users with \@types/bun */ /* prettier-ignore */ type BunRequestInit = globalThis.FetchRequestInit; -/** @ts-ignore For users with node-fetch@2 */ +/** @ts-ignore For users with node-fetch@2 */ /* prettier-ignore */ 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 */ +/** @ts-ignore For users with node-fetch@3, doesn't need file extension because types are at ./@types/index.d.ts */ /* prettier-ignore */ type NodeFetch3RequestInit = NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny | NotAny; -/** @ts-ignore For users who use Deno */ +/** @ts-ignore For users who use Deno */ /* prettier-ignore */ type FetchRequestInit = NonNullable[1]>; -/* eslint-enable */ type RequestInits = | NotAny diff --git a/src/internal/utils.ts b/src/internal/utils.ts index 3cbfacce..c591353b 100644 --- a/src/internal/utils.ts +++ b/src/internal/utils.ts @@ -6,3 +6,4 @@ export * from './utils/env'; export * from './utils/log'; export * from './utils/uuid'; export * from './utils/sleep'; +export * from './utils/query'; diff --git a/src/internal/utils/env.ts b/src/internal/utils/env.ts index 2d848007..cc5fa0fa 100644 --- a/src/internal/utils/env.ts +++ b/src/internal/utils/env.ts @@ -9,10 +9,10 @@ */ export const readEnv = (env: string): string | undefined => { if (typeof (globalThis as any).process !== 'undefined') { - return (globalThis as any).process.env?.[env]?.trim() ?? 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 (globalThis as any).Deno.env?.get?.(env)?.trim() || undefined; } return undefined; }; diff --git a/src/internal/utils/log.ts b/src/internal/utils/log.ts index a0504019..dec09bfd 100644 --- a/src/internal/utils/log.ts +++ b/src/internal/utils/log.ts @@ -106,8 +106,9 @@ export const formatRequestDetails = (details: { ([name, value]) => [ name, ( - name.toLowerCase() === 'x-api-key' || name.toLowerCase() === 'authorization' || + name.toLowerCase() === 'api-key' || + name.toLowerCase() === 'x-api-key' || name.toLowerCase() === 'cookie' || name.toLowerCase() === 'set-cookie' ) ? diff --git a/src/internal/utils/query.ts b/src/internal/utils/query.ts new file mode 100644 index 00000000..2c43c947 --- /dev/null +++ b/src/internal/utils/query.ts @@ -0,0 +1,23 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { BeagleError } from '../../core/error'; + +/** + * Basic re-implementation of `qs.stringify` for primitive types. + */ +export function stringifyQuery(query: object | Record) { + 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 BeagleError( + `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('&'); +} diff --git a/src/internal/utils/values.ts b/src/internal/utils/values.ts index 549111a6..2b5a832e 100644 --- a/src/internal/utils/values.ts +++ b/src/internal/utils/values.ts @@ -76,21 +76,21 @@ export const coerceBoolean = (value: unknown): boolean => { }; export const maybeCoerceInteger = (value: unknown): number | undefined => { - if (value === undefined) { + if (value == null) { return undefined; } return coerceInteger(value); }; export const maybeCoerceFloat = (value: unknown): number | undefined => { - if (value === undefined) { + if (value == null) { return undefined; } return coerceFloat(value); }; export const maybeCoerceBoolean = (value: unknown): boolean | undefined => { - if (value === undefined) { + if (value == null) { return undefined; } return coerceBoolean(value); diff --git a/src/resources/enrollments.ts b/src/resources/enrollments.ts index bb710ad3..510846d4 100644 --- a/src/resources/enrollments.ts +++ b/src/resources/enrollments.ts @@ -1,54 +1,99 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import { APIResource } from '../core/resource'; +import * as EnrollmentsAPI from './enrollments'; +import * as PropertyManagersAPI from './property-managers'; +import * as TenantsAPI from './tenants'; import { APIPromise } from '../core/api-promise'; -import { EnrollmentsPagination, type EnrollmentsPaginationParams, PagePromise } from '../core/pagination'; import { buildHeaders } from '../internal/headers'; import { RequestOptions } from '../internal/request-options'; import { path } from '../internal/utils/path'; +/** + * Handle the connections of tenants to plans over time. Create, list, retrieve, or lapse an enrollment records. Enrollments record the chosen plan, effective date, and optional notes. + */ export class Enrollments extends APIResource { /** * create a new enrollment for a tenant. + * + * @example + * ```ts + * const enrollment = await client.enrollments.create({ + * effectiveDate: '2025-11-10T19:50:20.638Z', + * plan: 'TLL_100K_CONTENTS_5K_ACV', + * propertyManagerId: 123, + * tenantId: 123, + * }); + * ``` */ - create(body: EnrollmentCreateParams, options?: RequestOptions): APIPromise { + create(body: EnrollmentCreateParams, options?: RequestOptions): APIPromise { return this._client.post('/api/enrollments', { body, ...options }); } /** * get a specific enrollment by its id. + * + * @example + * ```ts + * const enrollment = await client.enrollments.retrieve(123); + * ``` */ - retrieve(id: number | null, options?: RequestOptions): APIPromise { + retrieve(id: number, options?: RequestOptions): APIPromise { return this._client.get(path`/api/enrollments/${id}`, options); } /** * list all enrollments, this endpoint is paginated and allows for queries by * individual property manager. + * + * @example + * ```ts + * const enrollments = await client.enrollments.list(); + * ``` */ list( query: EnrollmentListParams | null | undefined = {}, options?: RequestOptions, - ): PagePromise { - return this._client.getAPIList('/api/enrollments', EnrollmentsPagination, { - query, - ...options, - }); + ): APIPromise { + return this._client.get('/api/enrollments', { query, ...options }); } /** * lapses a specific enrollment for a tenant, note that if a tenant has multiple * enrollments (e.g., SDR and TLL), each must be lapsed individually + * + * @example + * ```ts + * await client.enrollments.lapse(123); + * ``` */ - lapse(id: number | null, options?: RequestOptions): APIPromise { + lapse(id: number, options?: RequestOptions): APIPromise { return this._client.delete(path`/api/enrollments/${id}`, { ...options, headers: buildHeaders([{ Accept: '*/*' }, options?.headers]), }); } -} -export type EnrollmentsEnrollmentsPagination = EnrollmentsPagination; + /** + * get the certificate of enrollment for a given enrollment + * + * @example + * ```ts + * const response = + * await client.enrollments.retrieveCertificate(123); + * + * const content = await response.blob(); + * console.log(content); + * ``` + */ + retrieveCertificate(id: number, options?: RequestOptions): APIPromise { + return this._client.get(path`/api/enrollments/${id}/certificate`, { + ...options, + headers: buildHeaders([{ Accept: 'application/pdf' }, options?.headers]), + __binaryResponse: true, + }); + } +} export interface Enrollment { id: number; @@ -65,6 +110,16 @@ export interface Enrollment { propertyManagerId: number; + status: + | 'Premium Paying' + | 'Issued, Not Paid' + | 'Expired' + | 'Lapsed' + | 'Suspended' + | 'Cancelled' + | 'Not taken' + | 'Declined'; + tenantId: number; /** @@ -72,6 +127,36 @@ export interface Enrollment { * enrollments */ note?: string; + + product?: string; + + tenant?: TenantsAPI.Tenant; +} + +export interface EnrollmentCreateResponse { + data: Enrollment; + + success: true; +} + +export interface EnrollmentRetrieveResponse { + data: Enrollment; + + success: true; +} + +export interface EnrollmentListResponse { + data: EnrollmentListResponse.Data; + + success: true; +} + +export namespace EnrollmentListResponse { + export interface Data { + items: Array; + + pagination: PropertyManagersAPI.Pagination; + } } export interface EnrollmentCreateParams { @@ -94,16 +179,41 @@ export interface EnrollmentCreateParams { * enrollments */ note?: string; + + product?: string; + + /** + * the enrollment status — defaults to 'Issued, Not Paid' if not provided + */ + status?: 'Premium Paying' | 'Issued, Not Paid'; + + tenant?: TenantsAPI.Tenant; } -export interface EnrollmentListParams extends EnrollmentsPaginationParams { +export interface EnrollmentListParams { + /** + * Page number to fetch. + */ + page?: number; + + product?: string | null; + propertyManagerId?: number; + + /** + * Number of items per page. + */ + size?: number; + + status?: string | null; } export declare namespace Enrollments { export { type Enrollment as Enrollment, - type EnrollmentsEnrollmentsPagination as EnrollmentsEnrollmentsPagination, + type EnrollmentCreateResponse as EnrollmentCreateResponse, + type EnrollmentRetrieveResponse as EnrollmentRetrieveResponse, + type EnrollmentListResponse as EnrollmentListResponse, type EnrollmentCreateParams as EnrollmentCreateParams, type EnrollmentListParams as EnrollmentListParams, }; diff --git a/src/resources/index.ts b/src/resources/index.ts index e1d91bfd..981bef39 100644 --- a/src/resources/index.ts +++ b/src/resources/index.ts @@ -3,33 +3,41 @@ export { Enrollments, type Enrollment, + type EnrollmentCreateResponse, + type EnrollmentRetrieveResponse, + type EnrollmentListResponse, type EnrollmentCreateParams, type EnrollmentListParams, - type EnrollmentsEnrollmentsPagination, } from './enrollments'; export { InsuranceVerification, type InsuranceVerificationVerifyResponse, type InsuranceVerificationVerifyParams, } from './insurance-verification'; -export { Plans, type Plan, type PlanListResponse } from './plans'; +export { Plans, type Plan, type PlanRetrieveResponse, type PlanListResponse } from './plans'; export { PropertyManagers, type Pagination, type PropertyManager, + type PropertyManagerCreateResponse, + type PropertyManagerRetrieveResponse, + type PropertyManagerUpdateResponse, + type PropertyManagerListResponse, type PropertyManagerCreateParams, type PropertyManagerUpdateParams, type PropertyManagerListParams, - type PropertyManagersPropertyManagersPagination, } from './property-managers'; export { Tenants, type Address, type Contact, type Tenant, + type TenantCreateResponse, + type TenantRetrieveResponse, + type TenantUpdateResponse, + type TenantListResponse, type TenantCreateParams, type TenantUpdateParams, type TenantListParams, - type TenantsTenantsPagination, } from './tenants'; export { Webhook } from './webhook/webhook'; diff --git a/src/resources/insurance-verification.ts b/src/resources/insurance-verification.ts index 31443022..13360aa9 100644 --- a/src/resources/insurance-verification.ts +++ b/src/resources/insurance-verification.ts @@ -4,6 +4,9 @@ import { APIResource } from '../core/resource'; import { APIPromise } from '../core/api-promise'; import { RequestOptions } from '../internal/request-options'; +/** + * Trigger insurance document parsing and verifications on demand. This is currently under development please reach out for support integrating. + */ export class InsuranceVerification extends APIResource { /** * trigger a job to parse a tenants insurance document(s) diff --git a/src/resources/plans.ts b/src/resources/plans.ts index bc18e96f..970f3d3d 100644 --- a/src/resources/plans.ts +++ b/src/resources/plans.ts @@ -5,17 +5,23 @@ import { APIPromise } from '../core/api-promise'; import { RequestOptions } from '../internal/request-options'; import { path } from '../internal/utils/path'; +/** + * Retrieve a list of all plans or look up details by plan code. Each plan defines its name, description, rate, and any coverage values. + */ export class Plans extends APIResource { /** - * retrieve a specific plans details by its code. + * Retrieve a specific plan's details by its code. Plans are only returned when + * they are available to your API key, and pricing can vary by client + * configuration. */ - retrieve(code: string, options?: RequestOptions): APIPromise { + retrieve(code: string, options?: RequestOptions): APIPromise { return this._client.get(path`/api/plans/${code}`, options); } /** - * list all available plans, note this endpoint is currently unpaginated unlike all - * other list endpoints. + * List all insurance plans available to your API key. Plan availability, coverage + * details, and pricing can vary by client configuration. Use the plan's name/code + * when creating enrollments. */ list(options?: RequestOptions): APIPromise { return this._client.get('/api/plans', options); @@ -26,7 +32,7 @@ export interface Plan { description: string; /** - * the plans name/code, this is used when creating enrollments. + * the plan's name/code, this is used when creating enrollments. */ name: string; @@ -45,6 +51,26 @@ export interface Plan { */ liability?: number; + /** + * for approved-partner Rent Guarantee plans, the maximum monthly rent covered by + * this rent band. Rent Guarantee plan codes use the format + * RG*{term}M_RENT*{min}\_{max}; for example, RG_3M_RENT_750_1000 covers a 3-month + * term with monthly rent from $750 to $1,000. + */ + rentBandMax?: number; + + /** + * for approved-partner Rent Guarantee plans, the minimum monthly rent covered by + * this rent band. + */ + rentBandMin?: number; + + /** + * for approved-partner Rent Guarantee plans, the lease term in months. Match this + * to the tenant's lease term when choosing a plan. + */ + termMonths?: number; + /** * general value field, this is currently used for SDR and SDD plans for the * replacement or discount value. @@ -52,8 +78,22 @@ export interface Plan { value?: number; } -export type PlanListResponse = Array; +export interface PlanRetrieveResponse { + data: Plan; + + success: true; +} + +export interface PlanListResponse { + data: Array; + + success: true; +} export declare namespace Plans { - export { type Plan as Plan, type PlanListResponse as PlanListResponse }; + export { + type Plan as Plan, + type PlanRetrieveResponse as PlanRetrieveResponse, + type PlanListResponse as PlanListResponse, + }; } diff --git a/src/resources/property-managers.ts b/src/resources/property-managers.ts index 4853bc80..586e9943 100644 --- a/src/resources/property-managers.ts +++ b/src/resources/property-managers.ts @@ -1,61 +1,109 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import { APIResource } from '../core/resource'; +import * as PropertyManagersAPI from './property-managers'; import * as TenantsAPI from './tenants'; import { APIPromise } from '../core/api-promise'; -import { - PagePromise, - PropertyManagersPagination, - type PropertyManagersPaginationParams, -} from '../core/pagination'; import { buildHeaders } from '../internal/headers'; import { RequestOptions } from '../internal/request-options'; import { path } from '../internal/utils/path'; +/** + * Track and update your property managers. Create, list, retrieve, update, or delete property manager profiles. Each profile aggregates addresses and contact channels for billing, legal, and support. + */ export class PropertyManagers extends APIResource { /** * create a new property manager. + * + * @example + * ```ts + * const propertyManager = + * await client.propertyManagers.create({ + * addresses: [ + * { + * city: 'South Salt Lake', + * state: 'UT', + * street1: '123 Electric Ave.', + * zip: '84115', + * kind: 'place of business', + * }, + * ], + * contacts: [ + * { + * email: 'mr.milchick@example.com', + * name: { first: 'Seth', last: 'Milchick' }, + * kind: 'reporting', + * }, + * ], + * name: 'Lumon Apartments', + * }); + * ``` */ - create(body: PropertyManagerCreateParams, options?: RequestOptions): APIPromise { + create( + body: PropertyManagerCreateParams, + options?: RequestOptions, + ): APIPromise { return this._client.post('/api/property-managers', { body, ...options }); } /** * get a property manager by id. + * + * @example + * ```ts + * const propertyManager = + * await client.propertyManagers.retrieve(123); + * ``` */ - retrieve(id: number | null, options?: RequestOptions): APIPromise { + retrieve(id: number, options?: RequestOptions): APIPromise { return this._client.get(path`/api/property-managers/${id}`, options); } /** - * update an existing property manager by id, note that when updating contacts or - * addresses you need to send the whole array you want to replace them with. + * update an existing property manager by ID + * + * (Note that when updating **contacts** or **addresses** you need to send the + * whole array you want to replace them with) + * + * @example + * ```ts + * const propertyManager = + * await client.propertyManagers.update(123); + * ``` */ update( - id: number | null, + id: number, body: PropertyManagerUpdateParams, options?: RequestOptions, - ): APIPromise { + ): APIPromise { return this._client.patch(path`/api/property-managers/${id}`, { body, ...options }); } /** * list all property managers, note this endpoint is paginated. + * + * @example + * ```ts + * const propertyManagers = + * await client.propertyManagers.list(); + * ``` */ list( query: PropertyManagerListParams | null | undefined = {}, options?: RequestOptions, - ): PagePromise { - return this._client.getAPIList('/api/property-managers', PropertyManagersPagination, { - query, - ...options, - }); + ): APIPromise { + return this._client.get('/api/property-managers', { query, ...options }); } /** - * delete a property manager by id. + * delete a property manager by ID. + * + * @example + * ```ts + * await client.propertyManagers.delete(123); + * ``` */ - delete(id: number | null, options?: RequestOptions): APIPromise { + delete(id: number, options?: RequestOptions): APIPromise { return this._client.delete(path`/api/property-managers/${id}`, { ...options, headers: buildHeaders([{ Accept: '*/*' }, options?.headers]), @@ -63,8 +111,6 @@ export class PropertyManagers extends APIResource { } } -export type PropertyManagersPropertyManagersPagination = PropertyManagersPagination; - export interface Pagination { /** * Current page number. @@ -90,14 +136,30 @@ export interface Pagination { export interface PropertyManager { id: number; + /** + * street addresses for each Property + */ addresses: Array; + /** + * contact information for each Property Manager + */ contacts: Array; /** - * name of the property manager + * name of the Property Management Company */ name: string; + + /** + * unix timestamp (ms) of clickwrap agreement signature + */ + clickWrapAt?: number; + + /** + * total number of units managed by this property manager + */ + totalUnits?: number; } export namespace PropertyManager { @@ -110,15 +172,63 @@ export namespace PropertyManager { } } +export interface PropertyManagerCreateResponse { + data: PropertyManager; + + success: true; +} + +export interface PropertyManagerRetrieveResponse { + data: PropertyManager; + + success: true; +} + +export interface PropertyManagerUpdateResponse { + data: PropertyManager; + + success: true; +} + +export interface PropertyManagerListResponse { + data: PropertyManagerListResponse.Data; + + success: true; +} + +export namespace PropertyManagerListResponse { + export interface Data { + items: Array; + + pagination: PropertyManagersAPI.Pagination; + } +} + export interface PropertyManagerCreateParams { + /** + * street addresses for each Property + */ addresses: Array; + /** + * contact information for each Property Manager + */ contacts: Array; /** - * name of the property manager + * name of the Property Management Company */ name: string; + + /** + * unix timestamp (ms) of clickwrap agreement signature + */ + clickWrapAt?: number; + + /** + * total number of units managed by this property manager + */ + totalUnits?: number; } export namespace PropertyManagerCreateParams { @@ -132,14 +242,30 @@ export namespace PropertyManagerCreateParams { } export interface PropertyManagerUpdateParams { + /** + * street addresses for each Property + */ addresses?: Array; + /** + * unix timestamp (ms) of clickwrap agreement signature + */ + clickWrapAt?: number; + + /** + * contact information for each Property Manager + */ contacts?: Array; /** - * name of the property manager + * name of the Property Management Company */ name?: string; + + /** + * total number of units managed by this property manager + */ + totalUnits?: number; } export namespace PropertyManagerUpdateParams { @@ -152,13 +278,26 @@ export namespace PropertyManagerUpdateParams { } } -export interface PropertyManagerListParams extends PropertyManagersPaginationParams {} +export interface PropertyManagerListParams { + /** + * Page number to fetch. + */ + page?: number; + + /** + * Number of items per page. + */ + size?: number; +} export declare namespace PropertyManagers { export { type Pagination as Pagination, type PropertyManager as PropertyManager, - type PropertyManagersPropertyManagersPagination as PropertyManagersPropertyManagersPagination, + type PropertyManagerCreateResponse as PropertyManagerCreateResponse, + type PropertyManagerRetrieveResponse as PropertyManagerRetrieveResponse, + type PropertyManagerUpdateResponse as PropertyManagerUpdateResponse, + type PropertyManagerListResponse as PropertyManagerListResponse, type PropertyManagerCreateParams as PropertyManagerCreateParams, type PropertyManagerUpdateParams as PropertyManagerUpdateParams, type PropertyManagerListParams as PropertyManagerListParams, diff --git a/src/resources/tenants.ts b/src/resources/tenants.ts index 23ef673e..7a93fedd 100644 --- a/src/resources/tenants.ts +++ b/src/resources/tenants.ts @@ -1,49 +1,90 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import { APIResource } from '../core/resource'; +import * as TenantsAPI from './tenants'; +import * as PropertyManagersAPI from './property-managers'; import { APIPromise } from '../core/api-promise'; -import { PagePromise, TenantsPagination, type TenantsPaginationParams } from '../core/pagination'; import { buildHeaders } from '../internal/headers'; import { RequestOptions } from '../internal/request-options'; import { path } from '../internal/utils/path'; +/** + * Maintain your tenant directory and their primary contact and address. You can create, update, retrieve, list, or delete tenant records. Listings support pagination and filtering by property manager. + */ export class Tenants extends APIResource { /** * create a new tenant. + * + * @example + * ```ts + * const tenant = await client.tenants.create({ + * address: { + * city: 'South Salt Lake', + * state: 'UT', + * street1: '123 Main St.', + * zip: '84115', + * }, + * contact: { + * email: 'mark.s@example.com', + * name: { first: 'Mark', last: 'Scout' }, + * }, + * propertyManagerId: 123, + * }); + * ``` */ - create(body: TenantCreateParams, options?: RequestOptions): APIPromise { + create(body: TenantCreateParams, options?: RequestOptions): APIPromise { return this._client.post('/api/tenants', { body, ...options }); } /** * retrieve a single tenant by their id. + * + * @example + * ```ts + * const tenant = await client.tenants.retrieve(123); + * ``` */ - retrieve(id: number | null, options?: RequestOptions): APIPromise { + retrieve(id: number, options?: RequestOptions): APIPromise { return this._client.get(path`/api/tenants/${id}`, options); } /** * update an existing tenant by their id. + * + * @example + * ```ts + * const tenant = await client.tenants.update(123); + * ``` */ - update(id: number | null, body: TenantUpdateParams, options?: RequestOptions): APIPromise { + update(id: number, body: TenantUpdateParams, options?: RequestOptions): APIPromise { return this._client.patch(path`/api/tenants/${id}`, { body, ...options }); } /** * list all tenants, this endpoint is paginated and allows for queries by * individual property manager. + * + * @example + * ```ts + * const tenants = await client.tenants.list(); + * ``` */ list( query: TenantListParams | null | undefined = {}, options?: RequestOptions, - ): PagePromise { - return this._client.getAPIList('/api/tenants', TenantsPagination, { query, ...options }); + ): APIPromise { + return this._client.get('/api/tenants', { query, ...options }); } /** * delete an existing tenant by their id. + * + * @example + * ```ts + * await client.tenants.delete(123); + * ``` */ - delete(id: number | null, options?: RequestOptions): APIPromise { + delete(id: number, options?: RequestOptions): APIPromise { return this._client.delete(path`/api/tenants/${id}`, { ...options, headers: buildHeaders([{ Accept: '*/*' }, options?.headers]), @@ -51,8 +92,6 @@ export class Tenants extends APIResource { } } -export type TenantsTenantsPagination = TenantsPagination; - export interface Address { city: string; @@ -64,7 +103,7 @@ export interface Address { street1: string; /** - * 5 digit US zip code, ie 94104 + * US ZIP or ZIP+4. For example: '94104' or '94104-1234' */ zip: string; @@ -93,6 +132,42 @@ export interface Tenant { address: Address; contact: Contact; + + expectedMoveInDate?: string; + + expectedMoveOutDate?: string; +} + +export interface TenantCreateResponse { + data: Tenant; + + success: true; +} + +export interface TenantRetrieveResponse { + data: Tenant; + + success: true; +} + +export interface TenantUpdateResponse { + data: Tenant; + + success: true; +} + +export interface TenantListResponse { + data: TenantListResponse.Data; + + success: true; +} + +export namespace TenantListResponse { + export interface Data { + items: Array; + + pagination: PropertyManagersAPI.Pagination; + } } export interface TenantCreateParams { @@ -101,16 +176,34 @@ export interface TenantCreateParams { contact: Contact; propertyManagerId: number; + + expectedMoveInDate?: string; + + expectedMoveOutDate?: string; } export interface TenantUpdateParams { address?: Address; contact?: Contact; + + expectedMoveInDate?: string; + + expectedMoveOutDate?: string; } -export interface TenantListParams extends TenantsPaginationParams { +export interface TenantListParams { + /** + * Page number to fetch. + */ + page?: number; + propertyManagerId?: number; + + /** + * Number of items per page. + */ + size?: number; } export declare namespace Tenants { @@ -118,7 +211,10 @@ export declare namespace Tenants { type Address as Address, type Contact as Contact, type Tenant as Tenant, - type TenantsTenantsPagination as TenantsTenantsPagination, + type TenantCreateResponse as TenantCreateResponse, + type TenantRetrieveResponse as TenantRetrieveResponse, + type TenantUpdateResponse as TenantUpdateResponse, + type TenantListResponse as TenantListResponse, type TenantCreateParams as TenantCreateParams, type TenantUpdateParams as TenantUpdateParams, type TenantListParams as TenantListParams, diff --git a/src/resources/webhook/endpoints.ts b/src/resources/webhook/endpoints.ts index c9d6a495..2a196058 100644 --- a/src/resources/webhook/endpoints.ts +++ b/src/resources/webhook/endpoints.ts @@ -1,154 +1,5 @@ // 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 { - PagePromise, - WebhookEndpointsPagination, - type WebhookEndpointsPaginationParams, -} from '../../core/pagination'; -import { buildHeaders } from '../../internal/headers'; -import { RequestOptions } from '../../internal/request-options'; -import { path } from '../../internal/utils/path'; -export class Endpoints extends APIResource { - /** - * creates a new webhook target. - */ - create(body: EndpointCreateParams, options?: RequestOptions): APIPromise { - return this._client.post('/api/webhook/endpoints', { body, ...options }); - } - - /** - * retrieve a single webhook endpoint by its id. - */ - retrieve(id: number | null, options?: RequestOptions): APIPromise { - return this._client.get(path`/api/webhook/endpoints/${id}`, options); - } - - /** - * update an existing webhook endpoint by its id. - */ - update( - id: number | null, - body: EndpointUpdateParams, - options?: RequestOptions, - ): APIPromise { - return this._client.patch(path`/api/webhook/endpoints/${id}`, { body, ...options }); - } - - /** - * list all webhook endpoints, this endpoint is paginated and allows for queries by - * individual property manager. - */ - list( - query: EndpointListParams | null | undefined = {}, - options?: RequestOptions, - ): PagePromise { - return this._client.getAPIList( - '/api/webhook/endpoints', - WebhookEndpointsPagination, - { query, ...options }, - ); - } - - /** - * delete an existing webhook endpoint by its id. - */ - delete(id: number | null, options?: RequestOptions): APIPromise { - return this._client.delete(path`/api/webhook/endpoints/${id}`, { - ...options, - headers: buildHeaders([{ Accept: '*/*' }, options?.headers]), - }); - } -} - -export type EndpointListResponsesWebhookEndpointsPagination = - WebhookEndpointsPagination; - -export interface EndpointCreateResponse { - id: number; - - active: boolean; - - companyId: number; - - createdAt: string; - - updatedAt: string; - - url: string; -} - -export interface EndpointRetrieveResponse { - id: number; - - active: boolean; - - companyId: number; - - createdAt: string; - - updatedAt: string; - - url: string; -} - -export interface EndpointUpdateResponse { - id: number; - - active: boolean; - - companyId: number; - - createdAt: string; - - updatedAt: string; - - url: string; -} - -export interface EndpointListResponse { - id: number; - - active: boolean; - - companyId: number; - - createdAt: string; - - updatedAt: string; - - url: string; -} - -export interface EndpointCreateParams { - secret: string; - - url: string; - - active?: boolean; -} - -export interface EndpointUpdateParams { - secret: string; - - url: string; - - active?: boolean; -} - -export interface EndpointListParams extends WebhookEndpointsPaginationParams {} - -export declare namespace Endpoints { - export { - type EndpointCreateResponse as EndpointCreateResponse, - type EndpointRetrieveResponse as EndpointRetrieveResponse, - type EndpointUpdateResponse as EndpointUpdateResponse, - type EndpointListResponse as EndpointListResponse, - type EndpointListResponsesWebhookEndpointsPagination as EndpointListResponsesWebhookEndpointsPagination, - type EndpointCreateParams as EndpointCreateParams, - type EndpointUpdateParams as EndpointUpdateParams, - type EndpointListParams as EndpointListParams, - }; -} +export class Endpoints extends APIResource {} diff --git a/src/resources/webhook/index.ts b/src/resources/webhook/index.ts index ce1a32a7..f383a789 100644 --- a/src/resources/webhook/index.ts +++ b/src/resources/webhook/index.ts @@ -1,14 +1,4 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -export { - Endpoints, - type EndpointCreateResponse, - type EndpointRetrieveResponse, - type EndpointUpdateResponse, - type EndpointListResponse, - type EndpointCreateParams, - type EndpointUpdateParams, - type EndpointListParams, - type EndpointListResponsesWebhookEndpointsPagination, -} from './endpoints'; +export { Endpoints } from './endpoints'; export { Webhook } from './webhook'; diff --git a/src/resources/webhook/webhook.ts b/src/resources/webhook/webhook.ts index ef3cda87..10b70c91 100644 --- a/src/resources/webhook/webhook.ts +++ b/src/resources/webhook/webhook.ts @@ -2,17 +2,7 @@ import { APIResource } from '../../core/resource'; import * as EndpointsAPI from './endpoints'; -import { - EndpointCreateParams, - EndpointCreateResponse, - EndpointListParams, - EndpointListResponse, - EndpointListResponsesWebhookEndpointsPagination, - EndpointRetrieveResponse, - EndpointUpdateParams, - EndpointUpdateResponse, - Endpoints, -} from './endpoints'; +import { Endpoints } from './endpoints'; export class Webhook extends APIResource { endpoints: EndpointsAPI.Endpoints = new EndpointsAPI.Endpoints(this._client); @@ -21,15 +11,5 @@ export class Webhook extends APIResource { Webhook.Endpoints = Endpoints; export declare namespace Webhook { - export { - Endpoints as Endpoints, - type EndpointCreateResponse as EndpointCreateResponse, - type EndpointRetrieveResponse as EndpointRetrieveResponse, - type EndpointUpdateResponse as EndpointUpdateResponse, - type EndpointListResponse as EndpointListResponse, - type EndpointListResponsesWebhookEndpointsPagination as EndpointListResponsesWebhookEndpointsPagination, - type EndpointCreateParams as EndpointCreateParams, - type EndpointUpdateParams as EndpointUpdateParams, - type EndpointListParams as EndpointListParams, - }; + export { Endpoints as Endpoints }; } diff --git a/src/version.ts b/src/version.ts index 55a1a527..d66dc1ba 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1 +1 @@ -export const VERSION = '0.0.1-alpha.0'; +export const VERSION = '2.0.0'; // x-release-please-version diff --git a/tests/api-resources/enrollments.test.ts b/tests/api-resources/enrollments.test.ts index 48f121b4..8f1c3416 100644 --- a/tests/api-resources/enrollments.test.ts +++ b/tests/api-resources/enrollments.test.ts @@ -1,6 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import Beagle from 'beagle'; +import Beagle from '@corgi-tech/beagle'; const client = new Beagle({ apiKey: 'My API Key', @@ -8,13 +8,13 @@ const client = new Beagle({ }); describe('resource enrollments', () => { - // skipped: tests are disabled for the time being + // Mock server tests are disabled test.skip('create: only required params', async () => { const responsePromise = client.enrollments.create({ - effectiveDate: 'effectiveDate', - plan: 'plan', - propertyManagerId: 0, - tenantId: 0, + effectiveDate: '2025-11-10T19:50:20.638Z', + plan: 'TLL_100K_CONTENTS_5K_ACV', + propertyManagerId: 123, + tenantId: 123, }); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); @@ -25,20 +25,39 @@ describe('resource enrollments', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - // skipped: tests are disabled for the time being + // Mock server tests are disabled test.skip('create: required and optional params', async () => { const response = await client.enrollments.create({ - effectiveDate: 'effectiveDate', - plan: 'plan', - propertyManagerId: 0, - tenantId: 0, + effectiveDate: '2025-11-10T19:50:20.638Z', + plan: 'TLL_100K_CONTENTS_5K_ACV', + propertyManagerId: 123, + tenantId: 123, note: 'note', + product: 'product', + status: 'Issued, Not Paid', + tenant: { + id: 123, + address: { + city: 'South Salt Lake', + state: 'UT', + street1: '123 Main St.', + zip: '84115', + street2: 'Unit 3', + }, + contact: { + email: 'mark.s@example.com', + name: { first: 'Mark', last: 'Scout' }, + phone: '(123) 456-7890', + }, + expectedMoveInDate: 'expectedMoveInDate', + expectedMoveOutDate: 'expectedMoveOutDate', + }, }); }); - // skipped: tests are disabled for the time being + // Mock server tests are disabled test.skip('retrieve', async () => { - const responsePromise = client.enrollments.retrieve(42); + const responsePromise = client.enrollments.retrieve(123); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -48,7 +67,7 @@ describe('resource enrollments', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - // skipped: tests are disabled for the time being + // Mock server tests are disabled test.skip('list', async () => { const responsePromise = client.enrollments.list(); const rawResponse = await responsePromise.asResponse(); @@ -60,20 +79,26 @@ describe('resource enrollments', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - // skipped: tests are disabled for the time being + // Mock server 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( client.enrollments.list( - { page: 1, propertyManagerId: 1, size: 1 }, + { + page: 1, + product: 'product', + propertyManagerId: 1, + size: 1, + status: 'status', + }, { path: '/_stainless_unknown_path' }, ), ).rejects.toThrow(Beagle.NotFoundError); }); - // skipped: tests are disabled for the time being + // Mock server tests are disabled test.skip('lapse', async () => { - const responsePromise = client.enrollments.lapse(42); + const responsePromise = client.enrollments.lapse(123); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; diff --git a/tests/api-resources/insurance-verification.test.ts b/tests/api-resources/insurance-verification.test.ts index b35b20c0..134d48bd 100644 --- a/tests/api-resources/insurance-verification.test.ts +++ b/tests/api-resources/insurance-verification.test.ts @@ -1,6 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import Beagle from 'beagle'; +import Beagle from '@corgi-tech/beagle'; const client = new Beagle({ apiKey: 'My API Key', @@ -8,7 +8,7 @@ const client = new Beagle({ }); describe('resource insuranceVerification', () => { - // skipped: tests are disabled for the time being + // Mock server tests are disabled test.skip('verify: only required params', async () => { const responsePromise = client.insuranceVerification.verify({ propertyManagerId: 0, @@ -24,7 +24,7 @@ describe('resource insuranceVerification', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - // skipped: tests are disabled for the time being + // Mock server tests are disabled test.skip('verify: required and optional params', async () => { const response = await client.insuranceVerification.verify({ propertyManagerId: 0, diff --git a/tests/api-resources/plans.test.ts b/tests/api-resources/plans.test.ts index f0afb10e..345eb218 100644 --- a/tests/api-resources/plans.test.ts +++ b/tests/api-resources/plans.test.ts @@ -1,6 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import Beagle from 'beagle'; +import Beagle from '@corgi-tech/beagle'; const client = new Beagle({ apiKey: 'My API Key', @@ -8,7 +8,7 @@ const client = new Beagle({ }); describe('resource plans', () => { - // skipped: tests are disabled for the time being + // Mock server tests are disabled test.skip('retrieve', async () => { const responsePromise = client.plans.retrieve('code'); const rawResponse = await responsePromise.asResponse(); @@ -20,7 +20,7 @@ describe('resource plans', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - // skipped: tests are disabled for the time being + // Mock server tests are disabled test.skip('list', async () => { const responsePromise = client.plans.list(); const rawResponse = await responsePromise.asResponse(); diff --git a/tests/api-resources/property-managers.test.ts b/tests/api-resources/property-managers.test.ts index d833da9f..6b04f78a 100644 --- a/tests/api-resources/property-managers.test.ts +++ b/tests/api-resources/property-managers.test.ts @@ -1,6 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import Beagle from 'beagle'; +import Beagle from '@corgi-tech/beagle'; const client = new Beagle({ apiKey: 'My API Key', @@ -8,12 +8,26 @@ const client = new Beagle({ }); describe('resource propertyManagers', () => { - // skipped: tests are disabled for the time being + // Mock server tests are disabled test.skip('create: only required params', async () => { const responsePromise = client.propertyManagers.create({ - addresses: [{ city: 'city', state: 'xx', street1: 'street1', zip: '60513', kind: 'billing' }], - contacts: [{ email: 'dev@stainless.com', name: { first: 'first', last: 'last' }, kind: 'agreements' }], - name: 'name', + addresses: [ + { + city: 'South Salt Lake', + state: 'UT', + street1: '123 Electric Ave.', + zip: '84115', + kind: 'place of business', + }, + ], + contacts: [ + { + email: 'mr.milchick@example.com', + name: { first: 'Seth', last: 'Milchick' }, + kind: 'reporting', + }, + ], + name: 'Lumon Apartments', }); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); @@ -24,27 +38,36 @@ describe('resource propertyManagers', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - // skipped: tests are disabled for the time being + // Mock server tests are disabled test.skip('create: required and optional params', async () => { const response = await client.propertyManagers.create({ addresses: [ - { city: 'city', state: 'xx', street1: 'street1', zip: '60513', street2: 'street2', kind: 'billing' }, + { + city: 'South Salt Lake', + state: 'UT', + street1: '123 Electric Ave.', + zip: '84115', + street2: 'street2', + kind: 'place of business', + }, ], contacts: [ { - email: 'dev@stainless.com', - name: { first: 'first', last: 'last' }, - phone: 'phone', - kind: 'agreements', + email: 'mr.milchick@example.com', + name: { first: 'Seth', last: 'Milchick' }, + phone: '(123) 456-7890', + kind: 'reporting', }, ], - name: 'name', + name: 'Lumon Apartments', + clickWrapAt: 1773359774000, + totalUnits: 0, }); }); - // skipped: tests are disabled for the time being + // Mock server tests are disabled test.skip('retrieve', async () => { - const responsePromise = client.propertyManagers.retrieve(42); + const responsePromise = client.propertyManagers.retrieve(123); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -54,9 +77,9 @@ describe('resource propertyManagers', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - // skipped: tests are disabled for the time being + // Mock server tests are disabled test.skip('update', async () => { - const responsePromise = client.propertyManagers.update(42, {}); + const responsePromise = client.propertyManagers.update(123, {}); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -66,7 +89,7 @@ describe('resource propertyManagers', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - // skipped: tests are disabled for the time being + // Mock server tests are disabled test.skip('list', async () => { const responsePromise = client.propertyManagers.list(); const rawResponse = await responsePromise.asResponse(); @@ -78,7 +101,7 @@ describe('resource propertyManagers', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - // skipped: tests are disabled for the time being + // Mock server 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( @@ -86,9 +109,9 @@ describe('resource propertyManagers', () => { ).rejects.toThrow(Beagle.NotFoundError); }); - // skipped: tests are disabled for the time being + // Mock server tests are disabled test.skip('delete', async () => { - const responsePromise = client.propertyManagers.delete(42); + const responsePromise = client.propertyManagers.delete(123); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; diff --git a/tests/api-resources/tenants.test.ts b/tests/api-resources/tenants.test.ts index c7953d5b..814892f6 100644 --- a/tests/api-resources/tenants.test.ts +++ b/tests/api-resources/tenants.test.ts @@ -1,6 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import Beagle from 'beagle'; +import Beagle from '@corgi-tech/beagle'; const client = new Beagle({ apiKey: 'My API Key', @@ -8,12 +8,20 @@ const client = new Beagle({ }); describe('resource tenants', () => { - // skipped: tests are disabled for the time being + // Mock server tests are disabled test.skip('create: only required params', async () => { const responsePromise = client.tenants.create({ - address: { city: 'city', state: 'xx', street1: 'street1', zip: '60513' }, - contact: { email: 'dev@stainless.com', name: { first: 'first', last: 'last' } }, - propertyManagerId: 0, + address: { + city: 'South Salt Lake', + state: 'UT', + street1: '123 Main St.', + zip: '84115', + }, + contact: { + email: 'mark.s@example.com', + name: { first: 'Mark', last: 'Scout' }, + }, + propertyManagerId: 123, }); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); @@ -24,18 +32,30 @@ describe('resource tenants', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - // skipped: tests are disabled for the time being + // Mock server tests are disabled test.skip('create: required and optional params', async () => { const response = await client.tenants.create({ - address: { city: 'city', state: 'xx', street1: 'street1', zip: '60513', street2: 'street2' }, - contact: { email: 'dev@stainless.com', name: { first: 'first', last: 'last' }, phone: 'phone' }, - propertyManagerId: 0, + address: { + city: 'South Salt Lake', + state: 'UT', + street1: '123 Main St.', + zip: '84115', + street2: 'Unit 3', + }, + contact: { + email: 'mark.s@example.com', + name: { first: 'Mark', last: 'Scout' }, + phone: '(123) 456-7890', + }, + propertyManagerId: 123, + expectedMoveInDate: 'expectedMoveInDate', + expectedMoveOutDate: 'expectedMoveOutDate', }); }); - // skipped: tests are disabled for the time being + // Mock server tests are disabled test.skip('retrieve', async () => { - const responsePromise = client.tenants.retrieve(42); + const responsePromise = client.tenants.retrieve(123); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -45,9 +65,9 @@ describe('resource tenants', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - // skipped: tests are disabled for the time being + // Mock server tests are disabled test.skip('update', async () => { - const responsePromise = client.tenants.update(42, {}); + const responsePromise = client.tenants.update(123, {}); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; @@ -57,7 +77,7 @@ describe('resource tenants', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - // skipped: tests are disabled for the time being + // Mock server tests are disabled test.skip('list', async () => { const responsePromise = client.tenants.list(); const rawResponse = await responsePromise.asResponse(); @@ -69,17 +89,24 @@ describe('resource tenants', () => { expect(dataAndResponse.response).toBe(rawResponse); }); - // skipped: tests are disabled for the time being + // Mock server 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( - client.tenants.list({ page: 1, propertyManagerId: 1, size: 1 }, { path: '/_stainless_unknown_path' }), + client.tenants.list( + { + page: 1, + propertyManagerId: 1, + size: 1, + }, + { path: '/_stainless_unknown_path' }, + ), ).rejects.toThrow(Beagle.NotFoundError); }); - // skipped: tests are disabled for the time being + // Mock server tests are disabled test.skip('delete', async () => { - const responsePromise = client.tenants.delete(42); + const responsePromise = client.tenants.delete(123); const rawResponse = await responsePromise.asResponse(); expect(rawResponse).toBeInstanceOf(Response); const response = await responsePromise; diff --git a/tests/api-resources/webhook/endpoints.test.ts b/tests/api-resources/webhook/endpoints.test.ts deleted file mode 100644 index 9af27790..00000000 --- a/tests/api-resources/webhook/endpoints.test.ts +++ /dev/null @@ -1,99 +0,0 @@ -// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -import Beagle from 'beagle'; - -const client = new Beagle({ - apiKey: 'My API Key', - baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', -}); - -describe('resource endpoints', () => { - // skipped: tests are disabled for the time being - test.skip('create: only required params', async () => { - const responsePromise = client.webhook.endpoints.create({ secret: 'secret', url: 'https://example.com' }); - 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('create: required and optional params', async () => { - const response = await client.webhook.endpoints.create({ - secret: 'secret', - url: 'https://example.com', - active: true, - }); - }); - - // skipped: tests are disabled for the time being - test.skip('retrieve', async () => { - const responsePromise = client.webhook.endpoints.retrieve(42); - 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('update: only required params', async () => { - const responsePromise = client.webhook.endpoints.update(42, { - secret: 'secret', - url: 'https://example.com', - }); - 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('update: required and optional params', async () => { - const response = await client.webhook.endpoints.update(42, { - secret: 'secret', - url: 'https://example.com', - active: true, - }); - }); - - // skipped: tests are disabled for the time being - test.skip('list', async () => { - const responsePromise = client.webhook.endpoints.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.webhook.endpoints.list({ page: 1, size: 1 }, { path: '/_stainless_unknown_path' }), - ).rejects.toThrow(Beagle.NotFoundError); - }); - - // skipped: tests are disabled for the time being - test.skip('delete', async () => { - const responsePromise = client.webhook.endpoints.delete(42); - const rawResponse = await responsePromise.asResponse(); - expect(rawResponse).toBeInstanceOf(Response); - const response = await responsePromise; - expect(response).not.toBeInstanceOf(Response); - const dataAndResponse = await responsePromise.withResponse(); - expect(dataAndResponse.data).toBe(response); - expect(dataAndResponse.response).toBe(rawResponse); - }); -}); diff --git a/tests/base64.test.ts b/tests/base64.test.ts index 7c63aebf..4c73b5a0 100644 --- a/tests/base64.test.ts +++ b/tests/base64.test.ts @@ -1,4 +1,4 @@ -import { fromBase64, toBase64 } from 'beagle/internal/utils/base64'; +import { fromBase64, toBase64 } from '@corgi-tech/beagle/internal/utils/base64'; describe.each(['Buffer', 'atob'])('with %s', (mode) => { let originalBuffer: BufferConstructor; diff --git a/tests/buildHeaders.test.ts b/tests/buildHeaders.test.ts index eb1df780..aa7667cf 100644 --- a/tests/buildHeaders.test.ts +++ b/tests/buildHeaders.test.ts @@ -1,5 +1,5 @@ import { inspect } from 'node:util'; -import { buildHeaders, type HeadersLike, type NullableHeaders } from 'beagle/internal/headers'; +import { buildHeaders, type HeadersLike, type NullableHeaders } from '@corgi-tech/beagle/internal/headers'; function inspectNullableHeaders(headers: NullableHeaders) { return `NullableHeaders {${[ diff --git a/tests/form.test.ts b/tests/form.test.ts index f9487cde..778bee4c 100644 --- a/tests/form.test.ts +++ b/tests/form.test.ts @@ -1,5 +1,5 @@ -import { multipartFormRequestOptions, createForm } from 'beagle/internal/uploads'; -import { toFile } from 'beagle/core/uploads'; +import { multipartFormRequestOptions, createForm } from '@corgi-tech/beagle/internal/uploads'; +import { toFile } from '@corgi-tech/beagle/core/uploads'; describe('form data validation', () => { test('valid values do not error', async () => { diff --git a/tests/index.test.ts b/tests/index.test.ts index 345b9411..78a138ed 100644 --- a/tests/index.test.ts +++ b/tests/index.test.ts @@ -1,10 +1,10 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { APIPromise } from 'beagle/core/api-promise'; +import { APIPromise } from '@corgi-tech/beagle/core/api-promise'; import util from 'node:util'; -import Beagle from 'beagle'; -import { APIUserAbortError } from 'beagle'; +import Beagle from '@corgi-tech/beagle'; +import { APIUserAbortError } from '@corgi-tech/beagle'; const defaultFetch = fetch; describe('instantiate client', () => { @@ -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 }, @@ -87,7 +87,11 @@ describe('instantiate client', () => { error: jest.fn(), }; - const client = new Beagle({ logger: logger, logLevel: 'debug', apiKey: 'My API Key' }); + const client = new Beagle({ + logger: logger, + logLevel: 'debug', + apiKey: 'My API Key', + }); await forceAPIResponseForClient(client); expect(debugMock).toHaveBeenCalled(); @@ -107,7 +111,11 @@ describe('instantiate client', () => { error: jest.fn(), }; - const client = new Beagle({ logger: logger, logLevel: 'info', apiKey: 'My API Key' }); + const client = new Beagle({ + logger: logger, + logLevel: 'info', + apiKey: 'My API Key', + }); await forceAPIResponseForClient(client); expect(debugMock).not.toHaveBeenCalled(); @@ -157,7 +165,11 @@ describe('instantiate client', () => { }; process.env['BEAGLE_LOG'] = 'debug'; - const client = new Beagle({ logger: logger, logLevel: 'off', apiKey: 'My API Key' }); + const client = new Beagle({ + logger: logger, + logLevel: 'off', + apiKey: 'My API Key', + }); await forceAPIResponseForClient(client); expect(debugMock).not.toHaveBeenCalled(); @@ -173,7 +185,11 @@ describe('instantiate client', () => { }; process.env['BEAGLE_LOG'] = 'not a log level'; - const client = new Beagle({ logger: logger, logLevel: 'debug', apiKey: 'My API Key' }); + const client = new Beagle({ + logger: logger, + logLevel: 'debug', + apiKey: 'My API Key', + }); expect(client.logLevel).toBe('debug'); expect(warnMock).not.toHaveBeenCalled(); }); @@ -267,7 +283,11 @@ describe('instantiate client', () => { return new Response(JSON.stringify({}), { headers: { 'Content-Type': 'application/json' } }); }; - const client = new Beagle({ baseURL: 'http://localhost:5000/', apiKey: 'My API Key', fetch: testFetch }); + const client = new Beagle({ + baseURL: 'http://localhost:5000/', + apiKey: 'My API Key', + fetch: testFetch, + }); await client.patch('/foo'); expect(capturedRequest?.method).toEqual('PATCH'); @@ -320,7 +340,11 @@ describe('instantiate client', () => { `"Ambiguous URL; The \`baseURL\` option (or BEAGLE_BASE_URL env var) and the \`environment\` option are given. If you want to use the environment you must pass baseURL: null"`, ); - const client = new Beagle({ apiKey: 'My API Key', baseURL: null, environment: 'production' }); + const client = new Beagle({ + apiKey: 'My API Key', + baseURL: null, + environment: 'production', + }); expect(client.baseURL).toEqual('https://developer.beagleforpm.com'); }); @@ -357,8 +381,12 @@ describe('instantiate client', () => { }); describe('withOptions', () => { - test('creates a new client with overridden options', () => { - const client = new Beagle({ baseURL: 'http://localhost:5000/', maxRetries: 3, apiKey: 'My API Key' }); + test('creates a new client with overridden options', async () => { + const client = new Beagle({ + baseURL: 'http://localhost:5000/', + maxRetries: 3, + apiKey: 'My API Key', + }); const newClient = client.withOptions({ maxRetries: 5, @@ -378,7 +406,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 Beagle({ baseURL: 'http://localhost:5000/', defaultHeaders: { 'X-Test-Header': 'test-value' }, @@ -393,12 +421,16 @@ 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'); }); test('respects runtime property changes when creating new client', () => { - const client = new Beagle({ baseURL: 'http://localhost:5000/', timeout: 1000, apiKey: 'My API Key' }); + const client = new Beagle({ + baseURL: 'http://localhost:5000/', + timeout: 1000, + apiKey: 'My API Key', + }); // Modify the client properties directly after creation client.baseURL = 'http://localhost:6000/'; @@ -443,8 +475,8 @@ describe('request building', () => { const client = new Beagle({ 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' }, @@ -479,8 +511,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, @@ -503,7 +535,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, @@ -516,7 +548,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, @@ -544,7 +576,11 @@ describe('retries', () => { return new Response(JSON.stringify({ a: 1 }), { headers: { 'Content-Type': 'application/json' } }); }; - const client = new Beagle({ apiKey: 'My API Key', timeout: 10, fetch: testFetch }); + const client = new Beagle({ + apiKey: 'My API Key', + timeout: 10, + fetch: testFetch, + }); expect(await client.request({ path: '/foo', method: 'get' })).toEqual({ a: 1 }); expect(count).toEqual(2); @@ -574,7 +610,11 @@ describe('retries', () => { return new Response(JSON.stringify({ a: 1 }), { headers: { 'Content-Type': 'application/json' } }); }; - const client = new Beagle({ apiKey: 'My API Key', fetch: testFetch, maxRetries: 4 }); + const client = new Beagle({ + apiKey: 'My API Key', + fetch: testFetch, + maxRetries: 4, + }); expect(await client.request({ path: '/foo', method: 'get' })).toEqual({ a: 1 }); @@ -598,7 +638,11 @@ describe('retries', () => { capturedRequest = init; return new Response(JSON.stringify({ a: 1 }), { headers: { 'Content-Type': 'application/json' } }); }; - const client = new Beagle({ apiKey: 'My API Key', fetch: testFetch, maxRetries: 4 }); + const client = new Beagle({ + apiKey: 'My API Key', + fetch: testFetch, + maxRetries: 4, + }); expect( await client.request({ @@ -660,7 +704,11 @@ describe('retries', () => { capturedRequest = init; return new Response(JSON.stringify({ a: 1 }), { headers: { 'Content-Type': 'application/json' } }); }; - const client = new Beagle({ apiKey: 'My API Key', fetch: testFetch, maxRetries: 4 }); + const client = new Beagle({ + apiKey: 'My API Key', + fetch: testFetch, + maxRetries: 4, + }); expect( await client.request({ diff --git a/tests/path.test.ts b/tests/path.test.ts index 38937362..d53718b9 100644 --- a/tests/path.test.ts +++ b/tests/path.test.ts @@ -1,4 +1,4 @@ -import { createPathTagFunction, encodeURIPath } from 'beagle/internal/utils/path'; +import { createPathTagFunction, encodeURIPath } from '@corgi-tech/beagle/internal/utils/path'; import { inspect } from 'node:util'; import { runInNewContext } from 'node:vm'; diff --git a/tests/stringifyQuery.test.ts b/tests/stringifyQuery.test.ts index 01cba3b5..cbe61511 100644 --- a/tests/stringifyQuery.test.ts +++ b/tests/stringifyQuery.test.ts @@ -1,8 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { Beagle } from 'beagle'; - -const { stringifyQuery } = Beagle.prototype as any; +import { stringifyQuery } from '@corgi-tech/beagle/internal/utils/query'; describe(stringifyQuery, () => { for (const [input, expected] of [ @@ -15,7 +13,7 @@ describe(stringifyQuery, () => { 'e=f', )}=${encodeURIComponent('g&h')}`, ], - ]) { + ] as const) { it(`${JSON.stringify(input)} -> ${expected}`, () => { expect(stringifyQuery(input)).toEqual(expected); }); diff --git a/tests/uploads.test.ts b/tests/uploads.test.ts index a548f670..b995cd86 100644 --- a/tests/uploads.test.ts +++ b/tests/uploads.test.ts @@ -1,7 +1,6 @@ import fs from 'fs'; -import type { ResponseLike } from 'beagle/internal/to-file'; -import { toFile } from 'beagle/core/uploads'; -import { File } from 'node:buffer'; +import type { ResponseLike } from '@corgi-tech/beagle/internal/to-file'; +import { toFile } from '@corgi-tech/beagle/core/uploads'; class MyClass { name: string = 'foo'; @@ -97,7 +96,7 @@ describe('missing File error message', () => { }); test('is thrown', async () => { - const uploads = await import('beagle/core/uploads'); + const uploads = await import('@corgi-tech/beagle/core/uploads'); await expect( uploads.toFile(mockResponse({ url: 'https://example.com/my/audio.mp3' })), ).rejects.toMatchInlineSnapshot( diff --git a/tsconfig.build.json b/tsconfig.build.json index 0674d58f..c5a55ec2 100644 --- a/tsconfig.build.json +++ b/tsconfig.build.json @@ -5,8 +5,8 @@ "compilerOptions": { "rootDir": "./dist/src", "paths": { - "beagle/*": ["dist/src/*"], - "beagle": ["dist/src/index.ts"] + "@corgi-tech/beagle/*": ["./dist/src/*"], + "@corgi-tech/beagle": ["./dist/src/index.ts"] }, "noEmit": false, "declaration": true, diff --git a/tsconfig.json b/tsconfig.json index 29727585..2eab4fa2 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,10 +7,9 @@ "module": "commonjs", "moduleResolution": "node", "esModuleInterop": true, - "baseUrl": "./", "paths": { - "beagle/*": ["src/*"], - "beagle": ["src/index.ts"] + "@corgi-tech/beagle/*": ["./src/*"], + "@corgi-tech/beagle": ["./src/index.ts"] }, "noEmit": true, diff --git a/yarn.lock b/yarn.lock index 58c08d5f..06fc1085 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7,14 +7,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" @@ -46,155 +38,119 @@ 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== +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.28.6.tgz#72499312ec58b1e2245ba4a4f550c132be4982f7" + integrity sha512-JYgintcMjRiCvS8mMECzaEn+m3PfoQiyqukOMCCVQtoJGYJw8j/8LBJEiqkHLkfwCcs74E3pbAUFNg7d9VNJ+Q== dependencies: - "@babel/highlight" "^7.23.4" - chalk "^2.4.2" + "@babel/helper-validator-identifier" "^7.28.5" + js-tokens "^4.0.0" + picocolors "^1.1.1" -"@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/compat-data@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.28.6.tgz#103f466803fa0f059e82ccac271475470570d74c" + integrity sha512-2lfu57JtzctfIrcGMz992hyLlByuzgIk58+hhGCxjKZ3rWI82NnVLjXcaTqkI2NvlcvOskZaiZ5kjUALo3Lpxg== "@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" + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.28.6.tgz#531bf883a1126e53501ba46eb3bb414047af507f" + integrity sha512-H3mcG6ZDLTlYfaSNi0iOKkigqMFvkTKlGUYlD8GW7nNOYRrevuA46iTypPyv+06V3fEmvvazfntkBU34L0azAw== + dependencies: + "@babel/code-frame" "^7.28.6" + "@babel/generator" "^7.28.6" + "@babel/helper-compilation-targets" "^7.28.6" + "@babel/helper-module-transforms" "^7.28.6" + "@babel/helpers" "^7.28.6" + "@babel/parser" "^7.28.6" + "@babel/template" "^7.28.6" + "@babel/traverse" "^7.28.6" + "@babel/types" "^7.28.6" + "@jridgewell/remapping" "^2.3.5" 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== +"@babel/generator@^7.28.6", "@babel/generator@^7.7.2": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.28.6.tgz#48dcc65d98fcc8626a48f72b62e263d25fc3c3f1" + integrity sha512-lOoVRwADj8hjf7al89tvQ2a1lf53Z+7tiXMgpZJL3maQPDxh0DgLMN62B2MKUOFcoodBHLMbDM6WAbKgNy5Suw== + dependencies: + "@babel/parser" "^7.28.6" + "@babel/types" "^7.28.6" + "@jridgewell/gen-mapping" "^0.3.12" + "@jridgewell/trace-mapping" "^0.3.28" + jsesc "^3.0.2" + +"@babel/helper-compilation-targets@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz#32c4a3f41f12ed1532179b108a4d746e105c2b25" + integrity sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA== + dependencies: + "@babel/compat-data" "^7.28.6" + "@babel/helper-validator-option" "^7.27.1" + browserslist "^4.24.0" + lru-cache "^5.1.1" + semver "^6.3.1" + +"@babel/helper-globals@^7.28.0": + version "7.28.0" + resolved "https://registry.yarnpkg.com/@babel/helper-globals/-/helper-globals-7.28.0.tgz#b9430df2aa4e17bc28665eadeae8aa1d985e6674" + integrity sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw== + +"@babel/helper-module-imports@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz#60632cbd6ffb70b22823187201116762a03e2d5c" + integrity sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw== dependencies: - "@babel/types" "^7.23.6" - "@jridgewell/gen-mapping" "^0.3.2" - "@jridgewell/trace-mapping" "^0.3.17" - jsesc "^2.5.1" + "@babel/traverse" "^7.28.6" + "@babel/types" "^7.28.6" -"@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== +"@babel/helper-module-transforms@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz#9312d9d9e56edc35aeb6e95c25d4106b50b9eb1e" + integrity sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA== 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-module-imports" "^7.28.6" + "@babel/helper-validator-identifier" "^7.28.5" + "@babel/traverse" "^7.28.6" -"@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/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.28.6", "@babel/helper-plugin-utils@^7.8.0": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz#6f13ea251b68c8532e985fd532f28741a8af9ac8" + integrity sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug== + +"@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.28.5": + version "7.28.5" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz#010b6938fab7cb7df74aa2bbc06aa503b8fe5fb4" + integrity sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q== -"@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/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.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.28.6.tgz#fca903a313ae675617936e8998b814c415cbf5d7" + integrity sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw== + dependencies: + "@babel/template" "^7.28.6" + "@babel/types" "^7.28.6" + +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.28.6.tgz#f01a8885b7fa1e56dd8a155130226cd698ef13fd" + integrity sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ== + dependencies: + "@babel/types" "^7.28.6" "@babel/plugin-syntax-async-generators@^7.8.4": version "7.8.4" @@ -210,14 +166,28 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-class-properties@^7.8.3": +"@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-import-meta@^7.8.3": +"@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.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.28.6.tgz#b71d5914665f60124e133696f17cd7669062c503" + integrity sha512-jiLC0ma9XkQT3TKJ9uYvlakm66Pamywo+qwL+oL8HJOvc6TWdZXVfhqJr8CCzbSGUAbDOzlGHJC1U+vRfLQDvw== + dependencies: + "@babel/helper-plugin-utils" "^7.28.6" + +"@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== @@ -232,13 +202,13 @@ "@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== + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.28.6.tgz#f8ca28bbd84883b5fea0e447c635b81ba73997ee" + integrity sha512-wgEmr06G6sIpqr8YDwA2dSRTE3bJ+V0IfpzfSY3Lfgd7YWOaAdlykvJi13ZKBt8cZHfgH1IXN+CL656W3uUa4w== dependencies: - "@babel/helper-plugin-utils" "^7.22.5" + "@babel/helper-plugin-utils" "^7.28.6" -"@babel/plugin-syntax-logical-assignment-operators@^7.8.3": +"@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== @@ -252,7 +222,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-numeric-separator@^7.8.3": +"@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== @@ -280,7 +250,14 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-top-level-await@^7.8.3": +"@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== @@ -288,45 +265,41 @@ "@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" + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.28.6.tgz#c7b2ddf1d0a811145b1de800d1abd146af92e3a2" + integrity sha512-+nDNmQye7nlnuuHDboPbGm00Vqg3oO8niRRL27/4LYHUsHYh0zJ1xWOz0uRwNFmM1Avzk8wZbc6rdiYhomzv/A== + dependencies: + "@babel/helper-plugin-utils" "^7.28.6" + +"@babel/template@^7.28.6", "@babel/template@^7.3.3": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.28.6.tgz#0e7e56ecedb78aeef66ce7972b082fce76a23e57" + integrity sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ== + dependencies: + "@babel/code-frame" "^7.28.6" + "@babel/parser" "^7.28.6" + "@babel/types" "^7.28.6" + +"@babel/traverse@^7.28.6": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.28.6.tgz#871ddc79a80599a5030c53b1cc48cbe3a5583c2e" + integrity sha512-fgWX62k02qtjqdSNTAGxmKYY/7FSL9WAS1o2Hu5+I5m9T0yxZzr4cnrfXQ/MX0rIifthCSs6FKTlzYbJcPtMNg== + dependencies: + "@babel/code-frame" "^7.28.6" + "@babel/generator" "^7.28.6" + "@babel/helper-globals" "^7.28.0" + "@babel/parser" "^7.28.6" + "@babel/template" "^7.28.6" + "@babel/types" "^7.28.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== +"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.28.6", "@babel/types@^7.3.3": + version "7.28.6" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.28.6.tgz#c3e9377f1b155005bcc4c46020e7e394e13089df" + integrity sha512-0ZrskXVEHSWIqZM/sQZ4EV3jZJXRkio/WCxaqKZP1g//CEWEPSfeZFcms4XeKBCHU0ZKnIkdJeU/kF+eRp5lBg== dependencies: - "@babel/helper-string-parser" "^7.23.4" - "@babel/helper-validator-identifier" "^7.22.20" - to-fast-properties "^2.0.0" + "@babel/helper-string-parser" "^7.27.1" + "@babel/helper-validator-identifier" "^7.28.5" "@bcoe/v8-coverage@^0.2.3": version "0.2.3" @@ -350,45 +323,52 @@ dependencies: "@cspotcode/source-map-consumer" "0.8.0" -"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.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/eslint-utils@^4.8.0": + version "4.9.0" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.9.0.tgz#7308df158e064f0dd8b8fdb58aa14fa2a7f913b3" + integrity sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g== + dependencies: + eslint-visitor-keys "^3.4.3" + "@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== +"@eslint/config-array@^0.21.1": + version "0.21.1" + resolved "https://registry.yarnpkg.com/@eslint/config-array/-/config-array-0.21.1.tgz#7d1b0060fea407f8301e932492ba8c18aff29713" + integrity sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA== dependencies: - "@eslint/object-schema" "^2.1.6" + "@eslint/object-schema" "^2.1.7" 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== +"@eslint/config-helpers@^0.4.2": + version "0.4.2" + resolved "https://registry.yarnpkg.com/@eslint/config-helpers/-/config-helpers-0.4.2.tgz#1bd006ceeb7e2e55b2b773ab318d300e1a66aeda" + integrity sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw== dependencies: - "@types/json-schema" "^7.0.15" + "@eslint/core" "^0.17.0" -"@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== +"@eslint/core@^0.17.0": + version "0.17.0" + resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.17.0.tgz#77225820413d9617509da9342190a2019e78761c" + integrity sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ== 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== +"@eslint/eslintrc@^3.3.1": + version "3.3.3" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.3.3.tgz#26393a0806501b5e2b6a43aa588a4d8df67880ac" + integrity sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ== dependencies: ajv "^6.12.4" debug "^4.3.2" @@ -396,26 +376,26 @@ globals "^14.0.0" ignore "^5.2.0" import-fresh "^3.2.1" - js-yaml "^4.1.0" + js-yaml "^4.1.1" 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/js@9.39.1": + version "9.39.1" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.39.1.tgz#0dd59c3a9f40e3f1882975c321470969243e0164" + integrity sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw== -"@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/object-schema@^2.1.7": + version "2.1.7" + resolved "https://registry.yarnpkg.com/@eslint/object-schema/-/object-schema-2.1.7.tgz#6e2126a1347e86a4dedf8706ec67ff8e107ebbad" + integrity sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA== -"@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== +"@eslint/plugin-kit@^0.4.1": + version "0.4.1" + resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz#9779e3fd9b7ee33571a57435cf4335a1794a6cb2" + integrity sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA== dependencies: - "@eslint/core" "^0.10.0" + "@eslint/core" "^0.17.0" levn "^0.4.1" "@humanfs/core@^0.19.1": @@ -441,10 +421,10 @@ 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== +"@humanwhocodes/retry@^0.4.2": + version "0.4.3" + resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.4.3.tgz#c2b9d2e374ee62c586d3adbea87199b1d7a7a6ba" + integrity sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ== "@istanbuljs/load-nyc-config@^1.0.0": version "1.1.0" @@ -661,31 +641,38 @@ "@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== +"@jridgewell/gen-mapping@^0.3.12", "@jridgewell/gen-mapping@^0.3.5": + version "0.3.13" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz#6342a19f44347518c93e43b1ac69deb3c4656a1f" + integrity sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA== + dependencies: + "@jridgewell/sourcemap-codec" "^1.5.0" + "@jridgewell/trace-mapping" "^0.3.24" + +"@jridgewell/remapping@^2.3.5": + version "2.3.5" + resolved "https://registry.yarnpkg.com/@jridgewell/remapping/-/remapping-2.3.5.tgz#375c476d1972947851ba1e15ae8f123047445aa1" + integrity sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ== dependencies: - "@jridgewell/set-array" "^1.0.1" - "@jridgewell/sourcemap-codec" "^1.4.10" - "@jridgewell/trace-mapping" "^0.3.9" + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.24" "@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": +"@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": +"@jridgewell/sourcemap-codec@^1.5.0": + version "1.5.5" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz#6912b00d2c631c0d15ce1a7ab57cd657f2a8f8ba" + integrity sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og== + +"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.18": 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== @@ -693,6 +680,14 @@ "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" +"@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.28": + version "0.3.31" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz#db15d6781c931f3a251a3dac39501c98a6082fd0" + integrity sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw== + 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" @@ -714,11 +709,6 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@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" resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" @@ -938,11 +928,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" @@ -1057,6 +1047,11 @@ acorn@^8.14.0: resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.0.tgz#063e2c70cac5fb4f6467f0b11152e04c682795b0" integrity sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA== +acorn@^8.15.0: + version "8.15.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.15.0.tgz#a360898bc415edaac46c8241f6383975b930b816" + integrity sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg== + acorn@^8.4.1: version "8.7.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.0.tgz#90951fde0f8f09df93549481e5fc141445b791cf" @@ -1104,13 +1099,6 @@ ansi-regex@^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" @@ -1188,22 +1176,25 @@ babel-plugin-jest-hoist@^29.6.3: "@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== + version "1.2.0" + resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.2.0.tgz#20730d6cdc7dda5d89401cab10ac6a32067acde6" + integrity sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg== dependencies: "@babel/plugin-syntax-async-generators" "^7.8.4" "@babel/plugin-syntax-bigint" "^7.8.3" - "@babel/plugin-syntax-class-properties" "^7.8.3" - "@babel/plugin-syntax-import-meta" "^7.8.3" + "@babel/plugin-syntax-class-properties" "^7.12.13" + "@babel/plugin-syntax-class-static-block" "^7.14.5" + "@babel/plugin-syntax-import-attributes" "^7.24.7" + "@babel/plugin-syntax-import-meta" "^7.10.4" "@babel/plugin-syntax-json-strings" "^7.8.3" - "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4" "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" - "@babel/plugin-syntax-numeric-separator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.10.4" "@babel/plugin-syntax-object-rest-spread" "^7.8.3" "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" "@babel/plugin-syntax-optional-chaining" "^7.8.3" - "@babel/plugin-syntax-top-level-await" "^7.8.3" + "@babel/plugin-syntax-private-property-in-object" "^7.14.5" + "@babel/plugin-syntax-top-level-await" "^7.14.5" babel-preset-jest@^29.6.3: version "29.6.3" @@ -1218,18 +1209,15 @@ balanced-match@^1.0.0: 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" +baseline-browser-mapping@^2.9.0: + version "2.9.14" + resolved "https://registry.yarnpkg.com/baseline-browser-mapping/-/baseline-browser-mapping-2.9.14.tgz#3b6af0bc032445bca04de58caa9a87cfe921cbb3" + integrity sha512-B0xUquLkiGLgHhpPBqvl7GWegWBUNuujQ6kXd/r1U38ElPT6Ok8KZ8e+FpUGEc2ZoRQUzq/aUnaKFc/svWUGSg== -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== +brace-expansion@^2.0.2: + version "2.1.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.1.1.tgz#c68b1c4111c76aae3a6fba55d496cee10c39dad8" + integrity sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA== dependencies: balanced-match "^1.0.0" @@ -1240,15 +1228,16 @@ braces@^3.0.3: 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== +browserslist@^4.24.0: + version "4.28.1" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.28.1.tgz#7f534594628c53c63101079e27e40de490456a95" + integrity sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA== dependencies: - caniuse-lite "^1.0.30001565" - electron-to-chromium "^1.4.601" - node-releases "^2.0.14" - update-browserslist-db "^1.0.13" + baseline-browser-mapping "^2.9.0" + caniuse-lite "^1.0.30001759" + electron-to-chromium "^1.5.263" + node-releases "^2.0.27" + update-browserslist-db "^1.2.0" bs-logger@0.x: version "0.2.6" @@ -1284,19 +1273,10 @@ camelcase@^6.2.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" +caniuse-lite@^1.0.30001759: + version "1.0.30001764" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001764.tgz#03206c56469f236103b90f9ae10bcb8b9e1f6005" + integrity sha512-9JGuzl2M+vPL+pz70gtMF9sHdMFbY9FJaQBi186cHKH3pSzDvzoUJUPV6fqiKIMyXbud9ZLg4F3Yza1vJ1+93g== chalk@^4.0.0, chalk@^4.1.2: version "4.1.2" @@ -1385,13 +1365,6 @@ collect-v8-coverage@^1.0.0: 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" @@ -1399,11 +1372,6 @@ color-convert@^2.0.1: 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" @@ -1414,11 +1382,6 @@ commander@^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" @@ -1495,10 +1458,10 @@ diff@^4.0.1: 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== +electron-to-chromium@^1.5.263: + version "1.5.267" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.267.tgz#5d84f2df8cdb6bfe7e873706bb21bd4bfb574dc7" + integrity sha512-0Drusm6MVRXSOJpGbaSVgcQsuB4hEkMpHXaVstcPmhu5LIedxs1xNK/nIxmQIU/RPC0+1/o0AVZfBTkTNJOdUw== emittery@^0.13.1: version "0.13.1" @@ -1532,10 +1495,10 @@ escalade@^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== +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-string-regexp@^2.0.0: version "2.0.0" @@ -1547,28 +1510,20 @@ 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.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.11.7" - 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== +eslint-scope@^8.4.0: + version "8.4.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-8.4.0.tgz#88e646a207fad61436ffa39eb505147200655c82" + integrity sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg== dependencies: esrecurse "^4.3.0" estraverse "^5.2.0" -eslint-visitor-keys@^3.3.0: +eslint-visitor-keys@^3.3.0, 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== @@ -1578,31 +1533,36 @@ eslint-visitor-keys@^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== +eslint-visitor-keys@^4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz#4cfea60fe7dd0ad8e816e1ed026c1d5251b512c1" + integrity sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ== + +eslint@^9.39.1: + version "9.39.1" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.39.1.tgz#be8bf7c6de77dcc4252b5a8dcb31c2efff74a6e5" + integrity sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g== dependencies: - "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/eslint-utils" "^4.8.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" + "@eslint/config-array" "^0.21.1" + "@eslint/config-helpers" "^0.4.2" + "@eslint/core" "^0.17.0" + "@eslint/eslintrc" "^3.3.1" + "@eslint/js" "9.39.1" + "@eslint/plugin-kit" "^0.4.1" "@humanfs/node" "^0.16.6" "@humanwhocodes/module-importer" "^1.0.1" - "@humanwhocodes/retry" "^0.4.1" + "@humanwhocodes/retry" "^0.4.2" "@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" + eslint-scope "^8.4.0" + eslint-visitor-keys "^4.2.1" + espree "^10.4.0" esquery "^1.5.0" esutils "^2.0.2" fast-deep-equal "^3.1.3" @@ -1618,7 +1578,7 @@ eslint@^9.20.1: natural-compare "^1.4.0" optionator "^0.9.3" -espree@^10.0.1, espree@^10.3.0: +espree@^10.0.1: version "10.3.0" resolved "https://registry.yarnpkg.com/espree/-/espree-10.3.0.tgz#29267cf5b0cb98735b65e64ba07e0ed49d1eed8a" integrity sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg== @@ -1627,6 +1587,15 @@ espree@^10.0.1, espree@^10.3.0: acorn-jsx "^5.3.2" eslint-visitor-keys "^4.2.0" +espree@^10.4.0: + version "10.4.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-10.4.0.tgz#d54f4949d4629005a1fa168d937c3ff1f7e2a837" + integrity sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ== + dependencies: + acorn "^8.15.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^4.2.1" + esprima@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" @@ -1692,11 +1661,6 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^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" @@ -1857,11 +1821,6 @@ glob@^8.0.1: 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" @@ -1877,11 +1836,6 @@ graphemer@^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" @@ -2433,24 +2387,24 @@ js-tokens@^4.0.0: 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== + version "3.14.2" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.2.tgz#77485ce1dd7f33c061fd1b16ecea23b55fcb04b0" + integrity sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg== 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== +js-yaml@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.1.tgz#854c292467705b699476e1a2decc0c8a3458806b" + integrity sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA== 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== +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" @@ -2615,26 +2569,12 @@ mimic-fn@^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== +minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2, minimatch@^5.0.1, minimatch@^9.0.4, minimatch@^9.0.5: + version "9.0.9" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.9.tgz#9b0cb9fcb78087f6fd7eababe2511c4d3d60574e" + integrity sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg== 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" + brace-expansion "^2.0.2" minimist@^1.2.6: version "1.2.6" @@ -2685,10 +2625,10 @@ node-int64@^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== +node-releases@^2.0.27: + version "2.0.27" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.27.tgz#eedca519205cf20f650f61d56b070db111231e4e" + integrity sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA== normalize-path@^3.0.0: version "3.0.0" @@ -2856,11 +2796,6 @@ path-parse@^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" @@ -2888,13 +2823,6 @@ prelude-ls@^1.2.1: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== -prettier-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" @@ -3164,13 +3092,6 @@ superstruct@^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" @@ -3198,13 +3119,6 @@ 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.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.2.4" - test-exclude@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" @@ -3233,11 +3147,6 @@ tmpl@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" @@ -3283,9 +3192,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" - 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.11/tsc-multi.tgz": + version "1.1.11" + resolved "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.11/tsc-multi.tgz#010247051be13b55abdc98f787c017285149f4f2" dependencies: debug "^4.3.7" fast-glob "^3.3.2" @@ -3353,23 +3262,23 @@ 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" 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== +update-browserslist-db@^1.2.0: + version "1.2.3" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz#64d76db58713136acbeb4c49114366cc6cc2e80d" + integrity sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w== dependencies: - escalade "^3.1.1" - picocolors "^1.0.0" + escalade "^3.2.0" + picocolors "^1.1.1" uri-js@^4.2.2: version "4.4.1"