diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..43fd5a7 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,15 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/debian +{ + "name": "Development", + "image": "mcr.microsoft.com/devcontainers/typescript-node:latest", + "features": { + "ghcr.io/devcontainers/features/node:1": {} + }, + "postCreateCommand": "yarn install", + "customizations": { + "vscode": { + "extensions": ["esbenp.prettier-vscode"] + } + } +} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..8c21a27 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,81 @@ +name: CI +on: + push: + branches-ignore: + - 'generated' + - 'codegen/**' + - 'integrated/**' + - 'stl-preview-head/**' + - 'stl-preview-base/**' + +jobs: + lint: + timeout-minutes: 10 + name: lint + runs-on: ${{ github.repository == 'stainless-sdks/gitpod-typescript' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} + steps: + - uses: actions/checkout@v4 + + - name: Set up Node + uses: actions/setup-node@v4 + with: + node-version: '18' + + - name: Bootstrap + run: ./scripts/bootstrap + + - name: Check types + run: ./scripts/lint + + build: + timeout-minutes: 5 + name: build + runs-on: ${{ github.repository == 'stainless-sdks/gitpod-typescript' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} + permissions: + contents: read + id-token: write + steps: + - uses: actions/checkout@v4 + + - name: Set up Node + uses: actions/setup-node@v4 + with: + node-version: '18' + + - name: Bootstrap + run: ./scripts/bootstrap + + - name: Check build + run: ./scripts/build + + - name: Get GitHub OIDC Token + if: github.repository == 'stainless-sdks/gitpod-typescript' + id: github-oidc + uses: actions/github-script@v6 + with: + script: core.setOutput('github_token', await core.getIDToken()); + + - name: Upload tarball + if: github.repository == 'stainless-sdks/gitpod-typescript' + env: + URL: https://pkg.stainless.com/s + AUTH: ${{ steps.github-oidc.outputs.github_token }} + SHA: ${{ github.sha }} + run: ./scripts/utils/upload-artifact.sh + test: + timeout-minutes: 10 + name: test + runs-on: ${{ github.repository == 'stainless-sdks/gitpod-typescript' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }} + steps: + - uses: actions/checkout@v4 + + - name: Set up Node + uses: actions/setup-node@v4 + with: + node-version: '18' + + - name: Bootstrap + run: ./scripts/bootstrap + + - name: Run tests + run: ./scripts/test diff --git a/.github/workflows/publish-npm.yml b/.github/workflows/publish-npm.yml new file mode 100644 index 0000000..d11b246 --- /dev/null +++ b/.github/workflows/publish-npm.yml @@ -0,0 +1,32 @@ +# This workflow is triggered when a GitHub release is created. +# It can also be run manually to re-publish to NPM in case it failed for some reason. +# You can run this workflow by navigating to https://www.github.com/gitpod-io/gitpod-sdk-typescript/actions/workflows/publish-npm.yml +name: Publish NPM +on: + workflow_dispatch: + + release: + types: [published] + +jobs: + publish: + name: publish + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - name: Set up Node + uses: actions/setup-node@v3 + with: + node-version: '18' + + - name: Install dependencies + run: | + yarn install + + - name: Publish to NPM + run: | + bash ./bin/publish-npm + env: + NPM_TOKEN: ${{ secrets.GITPOD_NPM_TOKEN || secrets.NPM_TOKEN }} diff --git a/.github/workflows/release-doctor.yml b/.github/workflows/release-doctor.yml new file mode 100644 index 0000000..f875bac --- /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 == 'gitpod-io/gitpod-sdk-typescript' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch' || startsWith(github.head_ref, 'release-please') || github.head_ref == 'next') + + steps: + - uses: actions/checkout@v4 + + - name: Check release environment + run: | + bash ./bin/check-release-environment + env: + NPM_TOKEN: ${{ secrets.GITPOD_NPM_TOKEN || secrets.NPM_TOKEN }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d98d51a --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +.prism.log +node_modules +yarn-error.log +codegen.log +Brewfile.lock.json +dist +dist-deno +/*.tgz +.idea/ + diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 0000000..3548c5a --- /dev/null +++ b/.prettierignore @@ -0,0 +1,7 @@ +CHANGELOG.md +/ecosystem-tests/*/** +/node_modules +/deno + +# don't format tsc output, will break source maps +/dist diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 0000000..af75ada --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,7 @@ +{ + "arrowParens": "always", + "experimentalTernaries": true, + "printWidth": 110, + "singleQuote": true, + "trailingComma": "all" +} diff --git a/.release-please-manifest.json b/.release-please-manifest.json new file mode 100644 index 0000000..f1c1e58 --- /dev/null +++ b/.release-please-manifest.json @@ -0,0 +1,3 @@ +{ + ".": "0.5.0" +} diff --git a/.stats.yml b/.stats.yml new file mode 100644 index 0000000..9cdc117 --- /dev/null +++ b/.stats.yml @@ -0,0 +1,4 @@ +configured_endpoints: 116 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-2e6ddfc9da00e33fcf13baf0b67012b97f051fa986658ff114fde989e56caa94.yml +openapi_spec_hash: 5af02ea2008312d609394e548756e761 +config_hash: 60929489bdc1eaf979e7ef74fdd17b94 diff --git a/Brewfile b/Brewfile new file mode 100644 index 0000000..e4feee6 --- /dev/null +++ b/Brewfile @@ -0,0 +1 @@ +brew "node" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..60cc611 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,107 @@ +## Setting up the environment + +This repository uses [`yarn@v1`](https://classic.yarnpkg.com/lang/en/docs/install). +Other package managers may work but are not officially supported for development. + +To set up the repository, run: + +```sh +$ yarn +$ yarn build +``` + +This will install all the required dependencies and build output files to `dist/`. + +## Modifying/Adding code + +Most of the SDK is generated code. Modifications to code will be persisted between generations, but may +result in merge conflicts between manual patches and changes from the generator. The generator will never +modify the contents of the `src/lib/` and `examples/` directories. + +## Adding and running examples + +All files in the `examples/` directory are not modified by the generator and can be freely edited or added to. + +```ts +// add an example to examples/<your-example>.ts + +#!/usr/bin/env -S npm run tsn -T +… +``` + +```sh +$ chmod +x examples/<your-example>.ts +# run the example against your api +$ yarn tsn -T examples/<your-example>.ts +``` + +## Using the repository from source + +If you’d like to use the repository from source, you can either install from git or link to a cloned repository: + +To install via git: + +```sh +$ npm install git+ssh://git@github.com:gitpod-io/gitpod-sdk-typescript.git +``` + +Alternatively, to link a local copy of the repo: + +```sh +# Clone +$ git clone https://www.github.com/gitpod-io/gitpod-sdk-typescript +$ cd gitpod-sdk-typescript + +# With yarn +$ yarn link +$ cd ../my-package +$ yarn link @gitpod/sdk + +# With pnpm +$ pnpm link --global +$ cd ../my-package +$ pnpm link -—global @gitpod/sdk +``` + +## Running tests + +Most tests require you to [set up a mock server](https://github.com/stoplightio/prism) against the OpenAPI spec to run the tests. + +```sh +$ npx prism mock path/to/your/openapi.yml +``` + +```sh +$ yarn run test +``` + +## Linting and formatting + +This repository uses [prettier](https://www.npmjs.com/package/prettier) and +[eslint](https://www.npmjs.com/package/eslint) to format the code in the repository. + +To lint: + +```sh +$ yarn lint +``` + +To format and fix all lint issues automatically: + +```sh +$ yarn fix +``` + +## 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/gitpod-io/gitpod-sdk-typescript/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 new file mode 100644 index 0000000..01fd4f2 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2025 Gitpod + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md index 5882588..a2f50c6 100644 --- a/README.md +++ b/README.md @@ -1 +1,403 @@ -# gitpod-typescript \ No newline at end of file +# Gitpod TypeScript API Library + +[](https://npmjs.org/package/@gitpod/sdk)  + +This library provides convenient access to the Gitpod REST API from server-side TypeScript or JavaScript. + +The REST API documentation can be found on [docs.gitpod.io](https://docs.gitpod.io). The full API of this library can be found in [api.md](api.md). + +It is generated with [Stainless](https://www.stainless.com/). + +## Installation + +```sh +npm install @gitpod/sdk +``` + +## Usage + +The full API of this library can be found in [api.md](api.md). + +<!-- prettier-ignore --> +```js +import Gitpod from '@gitpod/sdk'; + +const client = new Gitpod({ + bearerToken: process.env['GITPOD_API_KEY'], // This is the default and can be omitted +}); + +async function main() { + const response = await client.identity.getAuthenticatedIdentity(); + + console.log(response.organizationId); +} + +main(); +``` + +### Request & Response types + +This library includes TypeScript definitions for all request params and response fields. You may import and use them like so: + +<!-- prettier-ignore --> +```ts +import Gitpod from '@gitpod/sdk'; + +const client = new Gitpod({ + bearerToken: process.env['GITPOD_API_KEY'], // This is the default and can be omitted +}); + +async function main() { + const response: Gitpod.IdentityGetAuthenticatedIdentityResponse = + await client.identity.getAuthenticatedIdentity(); +} + +main(); +``` + +Documentation for each method, request param, and response field are available in docstrings and will appear on hover in most modern editors. + +## Handling errors + +When the library is unable to connect to the API, +or if the API returns a non-success status code (i.e., 4xx or 5xx response), +a subclass of `APIError` will be thrown: + +<!-- prettier-ignore --> +```ts +async function main() { + const response = await client.identity.getAuthenticatedIdentity().catch(async (err) => { + if (err instanceof Gitpod.APIError) { + console.log(err.status); // 400 + console.log(err.name); // BadRequestError + console.log(err.headers); // {server: 'nginx', ...} + } else { + throw err; + } + }); +} + +main(); +``` + +Error codes are as follows: + +| Status Code | Error Type | +| ----------- | -------------------------- | +| 400 | `BadRequestError` | +| 401 | `AuthenticationError` | +| 403 | `PermissionDeniedError` | +| 404 | `NotFoundError` | +| 422 | `UnprocessableEntityError` | +| 429 | `RateLimitError` | +| >=500 | `InternalServerError` | +| N/A | `APIConnectionError` | + +### Retries + +Certain errors will be automatically retried 2 times by default, with a short exponential backoff. +Connection errors (for example, due to a network connectivity problem), 408 Request Timeout, 409 Conflict, +429 Rate Limit, and >=500 Internal errors will all be retried by default. + +You can use the `maxRetries` option to configure or disable this: + +<!-- prettier-ignore --> +```js +// Configure the default for all requests: +const client = new Gitpod({ + maxRetries: 0, // default is 2 +}); + +// Or, configure per-request: +await client.identity.getAuthenticatedIdentity({ + maxRetries: 5, +}); +``` + +### Timeouts + +Requests time out after 1 minute by default. You can configure this with a `timeout` option: + +<!-- prettier-ignore --> +```ts +// Configure the default for all requests: +const client = new Gitpod({ + timeout: 20 * 1000, // 20 seconds (default is 1 minute) +}); + +// Override per-request: +await client.identity.getAuthenticatedIdentity({ + timeout: 5 * 1000, +}); +``` + +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 Gitpod API are paginated. +You can use the `for await … of` syntax to iterate through items across all pages: + +```ts +async function fetchAllEnvironments(params) { + const allEnvironments = []; + // Automatically fetches more pages as needed. + for await (const environment of client.environments.list()) { + allEnvironments.push(environment); + } + return allEnvironments; +} +``` + +Alternatively, you can request a single page at a time: + +```ts +let page = await client.environments.list(); +for (const environment of page.environments) { + console.log(environment); +} + +// Convenience methods are provided for manually paginating: +while (page.hasNextPage()) { + page = await page.getNextPage(); + // ... +} +``` + +## Advanced Usage + +### Accessing raw Response data (e.g., headers) + +The "raw" `Response` returned by `fetch()` can be accessed through the `.asResponse()` method on the `APIPromise` type that all methods return. +This method returns as soon as the headers for a successful response are received and does not consume the response body, so you are free to write custom parsing or streaming logic. + +You can also use the `.withResponse()` method to get the raw `Response` along with the parsed data. +Unlike `.asResponse()` this method consumes the body, returning once it is parsed. + +<!-- prettier-ignore --> +```ts +const client = new Gitpod(); + +const response = await client.identity.getAuthenticatedIdentity().asResponse(); +console.log(response.headers.get('X-My-Header')); +console.log(response.statusText); // access the underlying Response object + +const { data: response, response: raw } = await client.identity.getAuthenticatedIdentity().withResponse(); +console.log(raw.headers.get('X-My-Header')); +console.log(response.organizationId); +``` + +### Logging + +> [!IMPORTANT] +> All log messages are intended for debugging only. The format and content of log messages +> may change between releases. + +#### Log levels + +The log level can be configured in two ways: + +1. Via the `GITPOD_LOG` environment variable +2. Using the `logLevel` client option (overrides the environment variable if set) + +```ts +import Gitpod from '@gitpod/sdk'; + +const client = new Gitpod({ + logLevel: 'debug', // Show all log messages +}); +``` + +Available log levels, from most to least verbose: + +- `'debug'` - Show debug messages, info, warnings, and errors +- `'info'` - Show info messages, warnings, and errors +- `'warn'` - Show warnings and errors (default) +- `'error'` - Show only errors +- `'off'` - Disable all logging + +At the `'debug'` level, all HTTP requests and responses are logged, including headers and bodies. +Some authentication-related headers are redacted, but sensitive data in request and response bodies +may still be visible. + +#### Custom logger + +By default, this library logs to `globalThis.console`. You can also provide a custom logger. +Most logging libraries are supported, including [pino](https://www.npmjs.com/package/pino), [winston](https://www.npmjs.com/package/winston), [bunyan](https://www.npmjs.com/package/bunyan), [consola](https://www.npmjs.com/package/consola), [signale](https://www.npmjs.com/package/signale), and [@std/log](https://jsr.io/@std/log). If your logger doesn't work, please open an issue. + +When providing a custom logger, the `logLevel` option still controls which messages are emitted, messages +below the configured level will not be sent to your logger. + +```ts +import Gitpod from '@gitpod/sdk'; +import pino from 'pino'; + +const logger = pino(); + +const client = new Gitpod({ + logger: logger.child({ name: 'Gitpod' }), + logLevel: 'debug', // Send all messages to pino, allowing it to filter +}); +``` + +### Making custom/undocumented requests + +This library is typed for convenient access to the documented API. If you need to access undocumented +endpoints, params, or response properties, the library can still be used. + +#### Undocumented endpoints + +To make requests to undocumented endpoints, you can use `client.get`, `client.post`, and other HTTP verbs. +Options on the client, such as retries, will be respected when making these requests. + +```ts +await client.post('/some/path', { + body: { some_prop: 'foo' }, + query: { some_query_arg: 'bar' }, +}); +``` + +#### Undocumented request params + +To make requests using undocumented parameters, you may use `// @ts-expect-error` on the undocumented +parameter. This library doesn't validate at runtime that the request matches the type, so any extra values you +send will be sent as-is. + +```ts +client.foo.create({ + foo: 'my_param', + bar: 12, + // @ts-expect-error baz is not yet public + baz: 'undocumented option', +}); +``` + +For requests with the `GET` verb, any extra params will be in the query, all other requests will send the +extra param in the body. + +If you want to explicitly send an extra argument, you can do so with the `query`, `body`, and `headers` request +options. + +#### Undocumented response properties + +To access undocumented response properties, you may access the response object with `// @ts-expect-error` on +the response object, or cast the response object to the requisite type. Like the request params, we do not +validate or strip extra properties from the response from the API. + +### Customizing the fetch client + +By default, this library expects a global `fetch` function is defined. + +If you want to use a different `fetch` function, you can either polyfill the global: + +```ts +import fetch from 'my-fetch'; + +globalThis.fetch = fetch; +``` + +Or pass it to the client: + +```ts +import Gitpod from '@gitpod/sdk'; +import fetch from 'my-fetch'; + +const client = new Gitpod({ fetch }); +``` + +### Fetch options + +If you want to set custom `fetch` options without overriding the `fetch` function, you can provide a `fetchOptions` object when instantiating the client or making a request. (Request-specific options override client options.) + +```ts +import Gitpod from '@gitpod/sdk'; + +const client = new Gitpod({ + fetchOptions: { + // `RequestInit` options + }, +}); +``` + +#### Configuring proxies + +To modify proxy behavior, you can provide custom `fetchOptions` that add runtime-specific proxy +options to requests: + +<img src="https://raw.githubusercontent.com/stainless-api/sdk-assets/refs/heads/main/node.svg" align="top" width="18" height="21"> **Node** <sup>[[docs](https://github.com/nodejs/undici/blob/main/docs/docs/api/ProxyAgent.md#example---proxyagent-with-fetch)]</sup> + +```ts +import Gitpod from '@gitpod/sdk'; +import * as undici from 'undici'; + +const proxyAgent = new undici.ProxyAgent('http://localhost:8888'); +const client = new Gitpod({ + fetchOptions: { + dispatcher: proxyAgent, + }, +}); +``` + +<img src="https://raw.githubusercontent.com/stainless-api/sdk-assets/refs/heads/main/bun.svg" align="top" width="18" height="21"> **Bun** <sup>[[docs](https://bun.sh/guides/http/proxy)]</sup> + +```ts +import Gitpod from '@gitpod/sdk'; + +const client = new Gitpod({ + fetchOptions: { + proxy: 'http://localhost:8888', + }, +}); +``` + +<img src="https://raw.githubusercontent.com/stainless-api/sdk-assets/refs/heads/main/deno.svg" align="top" width="18" height="21"> **Deno** <sup>[[docs](https://docs.deno.com/api/deno/~/Deno.createHttpClient)]</sup> + +```ts +import Gitpod from 'npm:@gitpod/sdk'; + +const httpClient = Deno.createHttpClient({ proxy: { url: 'http://localhost:8888' } }); +const client = new Gitpod({ + fetchOptions: { + client: httpClient, + }, +}); +``` + +## Frequently Asked Questions + +## Semantic versioning + +This package generally follows [SemVer](https://semver.org/spec/v2.0.0.html) conventions, though certain backwards-incompatible changes may be released as minor versions: + +1. Changes that only affect static types, without breaking runtime behavior. +2. Changes to library internals which are technically public but not intended or documented for external use. _(Please open a GitHub issue to let us know if you are relying on such internals.)_ +3. Changes that we do not expect to impact the vast majority of users in practice. + +We take backwards-compatibility seriously and work hard to ensure you can rely on a smooth upgrade experience. + +We are keen for your feedback; please open an [issue](https://www.github.com/gitpod-io/gitpod-sdk-typescript/issues) with questions, bugs, or suggestions. + +## Requirements + +TypeScript >= 4.9 is supported. + +The following runtimes are supported: + +- Web browsers (Up-to-date Chrome, Firefox, Safari, Edge, and more) +- Node.js 18 LTS or later ([non-EOL](https://endoflife.date/nodejs)) versions. +- Deno v1.28.0 or higher. +- Bun 1.0 or later. +- Cloudflare Workers. +- Vercel Edge Runtime. +- Jest 28 or greater with the `"node"` environment (`"jsdom"` is not supported at this time). +- Nitro v2.6 or greater. + +Note that React Native is not supported at this time. + +If you are interested in other runtime environments, please open or upvote an issue on GitHub. + +## Contributing + +See [the contributing documentation](./CONTRIBUTING.md). diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..2b0ed90 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,27 @@ +# Security Policy + +## Reporting Security Issues + +This SDK is generated by [Stainless Software Inc](http://stainless.com). Stainless takes security seriously, and encourages you to report any security vulnerability promptly so that appropriate action can be taken. + +To report a security issue, please contact the Stainless team at security@stainless.com. + +## Responsible Disclosure + +We appreciate the efforts of security researchers and individuals who help us maintain the security of +SDKs we generate. If you believe you have found a security vulnerability, please adhere to responsible +disclosure practices by allowing us a reasonable amount of time to investigate and address the issue +before making any information public. + +## Reporting Non-SDK Related Security Issues + +If you encounter security issues that are not directly related to SDKs but pertain to the services +or products provided by Gitpod please follow the respective company's security reporting guidelines. + +### Gitpod Terms and Policies + +Please contact dev-feedback@gitpod.com for any questions or concerns regarding security of our services. + +--- + +Thank you for helping us keep the SDKs and systems they interact with secure. diff --git a/api.md b/api.md new file mode 100644 index 0000000..516cda9 --- /dev/null +++ b/api.md @@ -0,0 +1,535 @@ +# Shared + +Types: + +- <code><a href="./src/resources/shared.ts">AutomationTrigger</a></code> +- <code><a href="./src/resources/shared.ts">EnvironmentClass</a></code> +- <code><a href="./src/resources/shared.ts">ErrorCode</a></code> +- <code><a href="./src/resources/shared.ts">FieldValue</a></code> +- <code><a href="./src/resources/shared.ts">OrganizationRole</a></code> +- <code><a href="./src/resources/shared.ts">Principal</a></code> +- <code><a href="./src/resources/shared.ts">RunsOn</a></code> +- <code><a href="./src/resources/shared.ts">Subject</a></code> +- <code><a href="./src/resources/shared.ts">Task</a></code> +- <code><a href="./src/resources/shared.ts">TaskExecution</a></code> +- <code><a href="./src/resources/shared.ts">TaskExecutionMetadata</a></code> +- <code><a href="./src/resources/shared.ts">TaskExecutionPhase</a></code> +- <code><a href="./src/resources/shared.ts">TaskExecutionSpec</a></code> +- <code><a href="./src/resources/shared.ts">TaskExecutionStatus</a></code> +- <code><a href="./src/resources/shared.ts">TaskMetadata</a></code> +- <code><a href="./src/resources/shared.ts">TaskSpec</a></code> +- <code><a href="./src/resources/shared.ts">UserStatus</a></code> + +# Accounts + +Types: + +- <code><a href="./src/resources/accounts.ts">Account</a></code> +- <code><a href="./src/resources/accounts.ts">AccountMembership</a></code> +- <code><a href="./src/resources/accounts.ts">JoinableOrganization</a></code> +- <code><a href="./src/resources/accounts.ts">LoginProvider</a></code> +- <code><a href="./src/resources/accounts.ts">AccountRetrieveResponse</a></code> +- <code><a href="./src/resources/accounts.ts">AccountDeleteResponse</a></code> +- <code><a href="./src/resources/accounts.ts">AccountGetSSOLoginURLResponse</a></code> + +Methods: + +- <code title="post /gitpod.v1.AccountService/GetAccount">client.accounts.<a href="./src/resources/accounts.ts">retrieve</a>({ ...params }) -> AccountRetrieveResponse</code> +- <code title="post /gitpod.v1.AccountService/DeleteAccount">client.accounts.<a href="./src/resources/accounts.ts">delete</a>({ ...params }) -> unknown</code> +- <code title="post /gitpod.v1.AccountService/GetSSOLoginURL">client.accounts.<a href="./src/resources/accounts.ts">getSSOLoginURL</a>({ ...params }) -> AccountGetSSOLoginURLResponse</code> +- <code title="post /gitpod.v1.AccountService/ListLoginProviders">client.accounts.<a href="./src/resources/accounts.ts">listLoginProviders</a>({ ...params }) -> LoginProvidersLoginProvidersPage</code> + +# Editors + +Types: + +- <code><a href="./src/resources/editors.ts">Editor</a></code> +- <code><a href="./src/resources/editors.ts">EditorRetrieveResponse</a></code> +- <code><a href="./src/resources/editors.ts">EditorResolveURLResponse</a></code> + +Methods: + +- <code title="post /gitpod.v1.EditorService/GetEditor">client.editors.<a href="./src/resources/editors.ts">retrieve</a>({ ...params }) -> EditorRetrieveResponse</code> +- <code title="post /gitpod.v1.EditorService/ListEditors">client.editors.<a href="./src/resources/editors.ts">list</a>({ ...params }) -> EditorsEditorsPage</code> +- <code title="post /gitpod.v1.EditorService/ResolveEditorURL">client.editors.<a href="./src/resources/editors.ts">resolveURL</a>({ ...params }) -> EditorResolveURLResponse</code> + +# Environments + +Types: + +- <code><a href="./src/resources/environments/environments.ts">AdmissionLevel</a></code> +- <code><a href="./src/resources/environments/environments.ts">Environment</a></code> +- <code><a href="./src/resources/environments/environments.ts">EnvironmentActivitySignal</a></code> +- <code><a href="./src/resources/environments/environments.ts">EnvironmentMetadata</a></code> +- <code><a href="./src/resources/environments/environments.ts">EnvironmentPhase</a></code> +- <code><a href="./src/resources/environments/environments.ts">EnvironmentSpec</a></code> +- <code><a href="./src/resources/environments/environments.ts">EnvironmentStatus</a></code> +- <code><a href="./src/resources/environments/environments.ts">EnvironmentCreateResponse</a></code> +- <code><a href="./src/resources/environments/environments.ts">EnvironmentRetrieveResponse</a></code> +- <code><a href="./src/resources/environments/environments.ts">EnvironmentUpdateResponse</a></code> +- <code><a href="./src/resources/environments/environments.ts">EnvironmentDeleteResponse</a></code> +- <code><a href="./src/resources/environments/environments.ts">EnvironmentCreateEnvironmentTokenResponse</a></code> +- <code><a href="./src/resources/environments/environments.ts">EnvironmentCreateFromProjectResponse</a></code> +- <code><a href="./src/resources/environments/environments.ts">EnvironmentCreateLogsTokenResponse</a></code> +- <code><a href="./src/resources/environments/environments.ts">EnvironmentMarkActiveResponse</a></code> +- <code><a href="./src/resources/environments/environments.ts">EnvironmentStartResponse</a></code> +- <code><a href="./src/resources/environments/environments.ts">EnvironmentStopResponse</a></code> + +Methods: + +- <code title="post /gitpod.v1.EnvironmentService/CreateEnvironment">client.environments.<a href="./src/resources/environments/environments.ts">create</a>({ ...params }) -> EnvironmentCreateResponse</code> +- <code title="post /gitpod.v1.EnvironmentService/GetEnvironment">client.environments.<a href="./src/resources/environments/environments.ts">retrieve</a>({ ...params }) -> EnvironmentRetrieveResponse</code> +- <code title="post /gitpod.v1.EnvironmentService/UpdateEnvironment">client.environments.<a href="./src/resources/environments/environments.ts">update</a>({ ...params }) -> unknown</code> +- <code title="post /gitpod.v1.EnvironmentService/ListEnvironments">client.environments.<a href="./src/resources/environments/environments.ts">list</a>({ ...params }) -> EnvironmentsEnvironmentsPage</code> +- <code title="post /gitpod.v1.EnvironmentService/DeleteEnvironment">client.environments.<a href="./src/resources/environments/environments.ts">delete</a>({ ...params }) -> unknown</code> +- <code title="post /gitpod.v1.EnvironmentService/CreateEnvironmentAccessToken">client.environments.<a href="./src/resources/environments/environments.ts">createEnvironmentToken</a>({ ...params }) -> EnvironmentCreateEnvironmentTokenResponse</code> +- <code title="post /gitpod.v1.EnvironmentService/CreateEnvironmentFromProject">client.environments.<a href="./src/resources/environments/environments.ts">createFromProject</a>({ ...params }) -> EnvironmentCreateFromProjectResponse</code> +- <code title="post /gitpod.v1.EnvironmentService/CreateEnvironmentLogsToken">client.environments.<a href="./src/resources/environments/environments.ts">createLogsToken</a>({ ...params }) -> EnvironmentCreateLogsTokenResponse</code> +- <code title="post /gitpod.v1.EnvironmentService/MarkEnvironmentActive">client.environments.<a href="./src/resources/environments/environments.ts">markActive</a>({ ...params }) -> unknown</code> +- <code title="post /gitpod.v1.EnvironmentService/StartEnvironment">client.environments.<a href="./src/resources/environments/environments.ts">start</a>({ ...params }) -> unknown</code> +- <code title="post /gitpod.v1.EnvironmentService/StopEnvironment">client.environments.<a href="./src/resources/environments/environments.ts">stop</a>({ ...params }) -> unknown</code> + +## Automations + +Types: + +- <code><a href="./src/resources/environments/automations/automations.ts">AutomationsFile</a></code> +- <code><a href="./src/resources/environments/automations/automations.ts">AutomationUpsertResponse</a></code> + +Methods: + +- <code title="post /gitpod.v1.EnvironmentAutomationService/UpsertAutomationsFile">client.environments.automations.<a href="./src/resources/environments/automations/automations.ts">upsert</a>({ ...params }) -> AutomationUpsertResponse</code> + +### Services + +Types: + +- <code><a href="./src/resources/environments/automations/services.ts">Service</a></code> +- <code><a href="./src/resources/environments/automations/services.ts">ServiceMetadata</a></code> +- <code><a href="./src/resources/environments/automations/services.ts">ServicePhase</a></code> +- <code><a href="./src/resources/environments/automations/services.ts">ServiceSpec</a></code> +- <code><a href="./src/resources/environments/automations/services.ts">ServiceStatus</a></code> +- <code><a href="./src/resources/environments/automations/services.ts">ServiceCreateResponse</a></code> +- <code><a href="./src/resources/environments/automations/services.ts">ServiceRetrieveResponse</a></code> +- <code><a href="./src/resources/environments/automations/services.ts">ServiceUpdateResponse</a></code> +- <code><a href="./src/resources/environments/automations/services.ts">ServiceDeleteResponse</a></code> +- <code><a href="./src/resources/environments/automations/services.ts">ServiceStartResponse</a></code> +- <code><a href="./src/resources/environments/automations/services.ts">ServiceStopResponse</a></code> + +Methods: + +- <code title="post /gitpod.v1.EnvironmentAutomationService/CreateService">client.environments.automations.services.<a href="./src/resources/environments/automations/services.ts">create</a>({ ...params }) -> ServiceCreateResponse</code> +- <code title="post /gitpod.v1.EnvironmentAutomationService/GetService">client.environments.automations.services.<a href="./src/resources/environments/automations/services.ts">retrieve</a>({ ...params }) -> ServiceRetrieveResponse</code> +- <code title="post /gitpod.v1.EnvironmentAutomationService/UpdateService">client.environments.automations.services.<a href="./src/resources/environments/automations/services.ts">update</a>({ ...params }) -> unknown</code> +- <code title="post /gitpod.v1.EnvironmentAutomationService/ListServices">client.environments.automations.services.<a href="./src/resources/environments/automations/services.ts">list</a>({ ...params }) -> ServicesServicesPage</code> +- <code title="post /gitpod.v1.EnvironmentAutomationService/DeleteService">client.environments.automations.services.<a href="./src/resources/environments/automations/services.ts">delete</a>({ ...params }) -> unknown</code> +- <code title="post /gitpod.v1.EnvironmentAutomationService/StartService">client.environments.automations.services.<a href="./src/resources/environments/automations/services.ts">start</a>({ ...params }) -> unknown</code> +- <code title="post /gitpod.v1.EnvironmentAutomationService/StopService">client.environments.automations.services.<a href="./src/resources/environments/automations/services.ts">stop</a>({ ...params }) -> unknown</code> + +### Tasks + +Types: + +- <code><a href="./src/resources/environments/automations/tasks/tasks.ts">TaskCreateResponse</a></code> +- <code><a href="./src/resources/environments/automations/tasks/tasks.ts">TaskRetrieveResponse</a></code> +- <code><a href="./src/resources/environments/automations/tasks/tasks.ts">TaskUpdateResponse</a></code> +- <code><a href="./src/resources/environments/automations/tasks/tasks.ts">TaskDeleteResponse</a></code> +- <code><a href="./src/resources/environments/automations/tasks/tasks.ts">TaskStartResponse</a></code> + +Methods: + +- <code title="post /gitpod.v1.EnvironmentAutomationService/CreateTask">client.environments.automations.tasks.<a href="./src/resources/environments/automations/tasks/tasks.ts">create</a>({ ...params }) -> TaskCreateResponse</code> +- <code title="post /gitpod.v1.EnvironmentAutomationService/GetTask">client.environments.automations.tasks.<a href="./src/resources/environments/automations/tasks/tasks.ts">retrieve</a>({ ...params }) -> TaskRetrieveResponse</code> +- <code title="post /gitpod.v1.EnvironmentAutomationService/UpdateTask">client.environments.automations.tasks.<a href="./src/resources/environments/automations/tasks/tasks.ts">update</a>({ ...params }) -> unknown</code> +- <code title="post /gitpod.v1.EnvironmentAutomationService/ListTasks">client.environments.automations.tasks.<a href="./src/resources/environments/automations/tasks/tasks.ts">list</a>({ ...params }) -> TasksTasksPage</code> +- <code title="post /gitpod.v1.EnvironmentAutomationService/DeleteTask">client.environments.automations.tasks.<a href="./src/resources/environments/automations/tasks/tasks.ts">delete</a>({ ...params }) -> unknown</code> +- <code title="post /gitpod.v1.EnvironmentAutomationService/StartTask">client.environments.automations.tasks.<a href="./src/resources/environments/automations/tasks/tasks.ts">start</a>({ ...params }) -> TaskStartResponse</code> + +#### Executions + +Types: + +- <code><a href="./src/resources/environments/automations/tasks/executions.ts">ExecutionRetrieveResponse</a></code> +- <code><a href="./src/resources/environments/automations/tasks/executions.ts">ExecutionStopResponse</a></code> + +Methods: + +- <code title="post /gitpod.v1.EnvironmentAutomationService/GetTaskExecution">client.environments.automations.tasks.executions.<a href="./src/resources/environments/automations/tasks/executions.ts">retrieve</a>({ ...params }) -> ExecutionRetrieveResponse</code> +- <code title="post /gitpod.v1.EnvironmentAutomationService/ListTaskExecutions">client.environments.automations.tasks.executions.<a href="./src/resources/environments/automations/tasks/executions.ts">list</a>({ ...params }) -> TaskExecutionsTaskExecutionsPage</code> +- <code title="post /gitpod.v1.EnvironmentAutomationService/StopTaskExecution">client.environments.automations.tasks.executions.<a href="./src/resources/environments/automations/tasks/executions.ts">stop</a>({ ...params }) -> unknown</code> + +## Classes + +Methods: + +- <code title="post /gitpod.v1.EnvironmentService/ListEnvironmentClasses">client.environments.classes.<a href="./src/resources/environments/classes.ts">list</a>({ ...params }) -> EnvironmentClassesEnvironmentClassesPage</code> + +# Events + +Types: + +- <code><a href="./src/resources/events.ts">ResourceOperation</a></code> +- <code><a href="./src/resources/events.ts">ResourceType</a></code> +- <code><a href="./src/resources/events.ts">EventListResponse</a></code> +- <code><a href="./src/resources/events.ts">EventWatchResponse</a></code> + +Methods: + +- <code title="post /gitpod.v1.EventService/ListAuditLogs">client.events.<a href="./src/resources/events.ts">list</a>({ ...params }) -> EventListResponsesEntriesPage</code> +- <code title="post /gitpod.v1.EventService/WatchEvents">client.events.<a href="./src/resources/events.ts">watch</a>({ ...params }) -> EventWatchResponse</code> + +# Groups + +Types: + +- <code><a href="./src/resources/groups.ts">Group</a></code> + +Methods: + +- <code title="post /gitpod.v1.GroupService/ListGroups">client.groups.<a href="./src/resources/groups.ts">list</a>({ ...params }) -> GroupsGroupsPage</code> + +# Identity + +Types: + +- <code><a href="./src/resources/identity.ts">IDTokenVersion</a></code> +- <code><a href="./src/resources/identity.ts">IdentityExchangeTokenResponse</a></code> +- <code><a href="./src/resources/identity.ts">IdentityGetAuthenticatedIdentityResponse</a></code> +- <code><a href="./src/resources/identity.ts">IdentityGetIDTokenResponse</a></code> + +Methods: + +- <code title="post /gitpod.v1.IdentityService/ExchangeToken">client.identity.<a href="./src/resources/identity.ts">exchangeToken</a>({ ...params }) -> IdentityExchangeTokenResponse</code> +- <code title="post /gitpod.v1.IdentityService/GetAuthenticatedIdentity">client.identity.<a href="./src/resources/identity.ts">getAuthenticatedIdentity</a>({ ...params }) -> IdentityGetAuthenticatedIdentityResponse</code> +- <code title="post /gitpod.v1.IdentityService/GetIDToken">client.identity.<a href="./src/resources/identity.ts">getIDToken</a>({ ...params }) -> IdentityGetIDTokenResponse</code> + +# Organizations + +Types: + +- <code><a href="./src/resources/organizations/organizations.ts">InviteDomains</a></code> +- <code><a href="./src/resources/organizations/organizations.ts">Organization</a></code> +- <code><a href="./src/resources/organizations/organizations.ts">OrganizationMember</a></code> +- <code><a href="./src/resources/organizations/organizations.ts">OrganizationTier</a></code> +- <code><a href="./src/resources/organizations/organizations.ts">OrganizationCreateResponse</a></code> +- <code><a href="./src/resources/organizations/organizations.ts">OrganizationRetrieveResponse</a></code> +- <code><a href="./src/resources/organizations/organizations.ts">OrganizationUpdateResponse</a></code> +- <code><a href="./src/resources/organizations/organizations.ts">OrganizationDeleteResponse</a></code> +- <code><a href="./src/resources/organizations/organizations.ts">OrganizationJoinResponse</a></code> +- <code><a href="./src/resources/organizations/organizations.ts">OrganizationLeaveResponse</a></code> +- <code><a href="./src/resources/organizations/organizations.ts">OrganizationSetRoleResponse</a></code> + +Methods: + +- <code title="post /gitpod.v1.OrganizationService/CreateOrganization">client.organizations.<a href="./src/resources/organizations/organizations.ts">create</a>({ ...params }) -> OrganizationCreateResponse</code> +- <code title="post /gitpod.v1.OrganizationService/GetOrganization">client.organizations.<a href="./src/resources/organizations/organizations.ts">retrieve</a>({ ...params }) -> OrganizationRetrieveResponse</code> +- <code title="post /gitpod.v1.OrganizationService/UpdateOrganization">client.organizations.<a href="./src/resources/organizations/organizations.ts">update</a>({ ...params }) -> OrganizationUpdateResponse</code> +- <code title="post /gitpod.v1.OrganizationService/DeleteOrganization">client.organizations.<a href="./src/resources/organizations/organizations.ts">delete</a>({ ...params }) -> unknown</code> +- <code title="post /gitpod.v1.OrganizationService/JoinOrganization">client.organizations.<a href="./src/resources/organizations/organizations.ts">join</a>({ ...params }) -> OrganizationJoinResponse</code> +- <code title="post /gitpod.v1.OrganizationService/LeaveOrganization">client.organizations.<a href="./src/resources/organizations/organizations.ts">leave</a>({ ...params }) -> unknown</code> +- <code title="post /gitpod.v1.OrganizationService/ListMembers">client.organizations.<a href="./src/resources/organizations/organizations.ts">listMembers</a>({ ...params }) -> OrganizationMembersMembersPage</code> +- <code title="post /gitpod.v1.OrganizationService/SetRole">client.organizations.<a href="./src/resources/organizations/organizations.ts">setRole</a>({ ...params }) -> unknown</code> + +## DomainVerifications + +Types: + +- <code><a href="./src/resources/organizations/domain-verifications.ts">DomainVerification</a></code> +- <code><a href="./src/resources/organizations/domain-verifications.ts">DomainVerificationState</a></code> +- <code><a href="./src/resources/organizations/domain-verifications.ts">DomainVerificationCreateResponse</a></code> +- <code><a href="./src/resources/organizations/domain-verifications.ts">DomainVerificationRetrieveResponse</a></code> +- <code><a href="./src/resources/organizations/domain-verifications.ts">DomainVerificationDeleteResponse</a></code> +- <code><a href="./src/resources/organizations/domain-verifications.ts">DomainVerificationVerifyResponse</a></code> + +Methods: + +- <code title="post /gitpod.v1.OrganizationService/CreateDomainVerification">client.organizations.domainVerifications.<a href="./src/resources/organizations/domain-verifications.ts">create</a>({ ...params }) -> DomainVerificationCreateResponse</code> +- <code title="post /gitpod.v1.OrganizationService/GetDomainVerification">client.organizations.domainVerifications.<a href="./src/resources/organizations/domain-verifications.ts">retrieve</a>({ ...params }) -> DomainVerificationRetrieveResponse</code> +- <code title="post /gitpod.v1.OrganizationService/ListDomainVerifications">client.organizations.domainVerifications.<a href="./src/resources/organizations/domain-verifications.ts">list</a>({ ...params }) -> DomainVerificationsDomainVerificationsPage</code> +- <code title="post /gitpod.v1.OrganizationService/DeleteDomainVerification">client.organizations.domainVerifications.<a href="./src/resources/organizations/domain-verifications.ts">delete</a>({ ...params }) -> unknown</code> +- <code title="post /gitpod.v1.OrganizationService/VerifyDomain">client.organizations.domainVerifications.<a href="./src/resources/organizations/domain-verifications.ts">verify</a>({ ...params }) -> DomainVerificationVerifyResponse</code> + +## Invites + +Types: + +- <code><a href="./src/resources/organizations/invites.ts">OrganizationInvite</a></code> +- <code><a href="./src/resources/organizations/invites.ts">InviteCreateResponse</a></code> +- <code><a href="./src/resources/organizations/invites.ts">InviteRetrieveResponse</a></code> +- <code><a href="./src/resources/organizations/invites.ts">InviteGetSummaryResponse</a></code> + +Methods: + +- <code title="post /gitpod.v1.OrganizationService/CreateOrganizationInvite">client.organizations.invites.<a href="./src/resources/organizations/invites.ts">create</a>({ ...params }) -> InviteCreateResponse</code> +- <code title="post /gitpod.v1.OrganizationService/GetOrganizationInvite">client.organizations.invites.<a href="./src/resources/organizations/invites.ts">retrieve</a>({ ...params }) -> InviteRetrieveResponse</code> +- <code title="post /gitpod.v1.OrganizationService/GetOrganizationInviteSummary">client.organizations.invites.<a href="./src/resources/organizations/invites.ts">getSummary</a>({ ...params }) -> InviteGetSummaryResponse</code> + +## Policies + +Types: + +- <code><a href="./src/resources/organizations/policies.ts">OrganizationPolicies</a></code> +- <code><a href="./src/resources/organizations/policies.ts">PolicyRetrieveResponse</a></code> +- <code><a href="./src/resources/organizations/policies.ts">PolicyUpdateResponse</a></code> + +Methods: + +- <code title="post /gitpod.v1.OrganizationService/GetOrganizationPolicies">client.organizations.policies.<a href="./src/resources/organizations/policies.ts">retrieve</a>({ ...params }) -> PolicyRetrieveResponse</code> +- <code title="post /gitpod.v1.OrganizationService/UpdateOrganizationPolicies">client.organizations.policies.<a href="./src/resources/organizations/policies.ts">update</a>({ ...params }) -> unknown</code> + +## SSOConfigurations + +Types: + +- <code><a href="./src/resources/organizations/sso-configurations.ts">ProviderType</a></code> +- <code><a href="./src/resources/organizations/sso-configurations.ts">SSOConfiguration</a></code> +- <code><a href="./src/resources/organizations/sso-configurations.ts">SSOConfigurationState</a></code> +- <code><a href="./src/resources/organizations/sso-configurations.ts">SSOConfigurationCreateResponse</a></code> +- <code><a href="./src/resources/organizations/sso-configurations.ts">SSOConfigurationRetrieveResponse</a></code> +- <code><a href="./src/resources/organizations/sso-configurations.ts">SSOConfigurationUpdateResponse</a></code> +- <code><a href="./src/resources/organizations/sso-configurations.ts">SSOConfigurationDeleteResponse</a></code> + +Methods: + +- <code title="post /gitpod.v1.OrganizationService/CreateSSOConfiguration">client.organizations.ssoConfigurations.<a href="./src/resources/organizations/sso-configurations.ts">create</a>({ ...params }) -> SSOConfigurationCreateResponse</code> +- <code title="post /gitpod.v1.OrganizationService/GetSSOConfiguration">client.organizations.ssoConfigurations.<a href="./src/resources/organizations/sso-configurations.ts">retrieve</a>({ ...params }) -> SSOConfigurationRetrieveResponse</code> +- <code title="post /gitpod.v1.OrganizationService/UpdateSSOConfiguration">client.organizations.ssoConfigurations.<a href="./src/resources/organizations/sso-configurations.ts">update</a>({ ...params }) -> unknown</code> +- <code title="post /gitpod.v1.OrganizationService/ListSSOConfigurations">client.organizations.ssoConfigurations.<a href="./src/resources/organizations/sso-configurations.ts">list</a>({ ...params }) -> SSOConfigurationsSSOConfigurationsPage</code> +- <code title="post /gitpod.v1.OrganizationService/DeleteSSOConfiguration">client.organizations.ssoConfigurations.<a href="./src/resources/organizations/sso-configurations.ts">delete</a>({ ...params }) -> unknown</code> + +# Projects + +Types: + +- <code><a href="./src/resources/projects/projects.ts">EnvironmentInitializer</a></code> +- <code><a href="./src/resources/projects/projects.ts">Project</a></code> +- <code><a href="./src/resources/projects/projects.ts">ProjectEnvironmentClass</a></code> +- <code><a href="./src/resources/projects/projects.ts">ProjectMetadata</a></code> +- <code><a href="./src/resources/projects/projects.ts">ProjectCreateResponse</a></code> +- <code><a href="./src/resources/projects/projects.ts">ProjectRetrieveResponse</a></code> +- <code><a href="./src/resources/projects/projects.ts">ProjectUpdateResponse</a></code> +- <code><a href="./src/resources/projects/projects.ts">ProjectDeleteResponse</a></code> +- <code><a href="./src/resources/projects/projects.ts">ProjectCreateFromEnvironmentResponse</a></code> + +Methods: + +- <code title="post /gitpod.v1.ProjectService/CreateProject">client.projects.<a href="./src/resources/projects/projects.ts">create</a>({ ...params }) -> ProjectCreateResponse</code> +- <code title="post /gitpod.v1.ProjectService/GetProject">client.projects.<a href="./src/resources/projects/projects.ts">retrieve</a>({ ...params }) -> ProjectRetrieveResponse</code> +- <code title="post /gitpod.v1.ProjectService/UpdateProject">client.projects.<a href="./src/resources/projects/projects.ts">update</a>({ ...params }) -> ProjectUpdateResponse</code> +- <code title="post /gitpod.v1.ProjectService/ListProjects">client.projects.<a href="./src/resources/projects/projects.ts">list</a>({ ...params }) -> ProjectsProjectsPage</code> +- <code title="post /gitpod.v1.ProjectService/DeleteProject">client.projects.<a href="./src/resources/projects/projects.ts">delete</a>({ ...params }) -> unknown</code> +- <code title="post /gitpod.v1.ProjectService/CreateProjectFromEnvironment">client.projects.<a href="./src/resources/projects/projects.ts">createFromEnvironment</a>({ ...params }) -> ProjectCreateFromEnvironmentResponse</code> + +## Policies + +Types: + +- <code><a href="./src/resources/projects/policies.ts">ProjectPolicy</a></code> +- <code><a href="./src/resources/projects/policies.ts">ProjectRole</a></code> +- <code><a href="./src/resources/projects/policies.ts">PolicyCreateResponse</a></code> +- <code><a href="./src/resources/projects/policies.ts">PolicyUpdateResponse</a></code> +- <code><a href="./src/resources/projects/policies.ts">PolicyDeleteResponse</a></code> + +Methods: + +- <code title="post /gitpod.v1.ProjectService/CreateProjectPolicy">client.projects.policies.<a href="./src/resources/projects/policies.ts">create</a>({ ...params }) -> PolicyCreateResponse</code> +- <code title="post /gitpod.v1.ProjectService/UpdateProjectPolicy">client.projects.policies.<a href="./src/resources/projects/policies.ts">update</a>({ ...params }) -> PolicyUpdateResponse</code> +- <code title="post /gitpod.v1.ProjectService/ListProjectPolicies">client.projects.policies.<a href="./src/resources/projects/policies.ts">list</a>({ ...params }) -> ProjectPoliciesPoliciesPage</code> +- <code title="post /gitpod.v1.ProjectService/DeleteProjectPolicy">client.projects.policies.<a href="./src/resources/projects/policies.ts">delete</a>({ ...params }) -> unknown</code> + +# Runners + +Types: + +- <code><a href="./src/resources/runners/runners.ts">LogLevel</a></code> +- <code><a href="./src/resources/runners/runners.ts">MetricsConfiguration</a></code> +- <code><a href="./src/resources/runners/runners.ts">Runner</a></code> +- <code><a href="./src/resources/runners/runners.ts">RunnerCapability</a></code> +- <code><a href="./src/resources/runners/runners.ts">RunnerConfiguration</a></code> +- <code><a href="./src/resources/runners/runners.ts">RunnerKind</a></code> +- <code><a href="./src/resources/runners/runners.ts">RunnerPhase</a></code> +- <code><a href="./src/resources/runners/runners.ts">RunnerProvider</a></code> +- <code><a href="./src/resources/runners/runners.ts">RunnerReleaseChannel</a></code> +- <code><a href="./src/resources/runners/runners.ts">RunnerSpec</a></code> +- <code><a href="./src/resources/runners/runners.ts">RunnerStatus</a></code> +- <code><a href="./src/resources/runners/runners.ts">RunnerCreateResponse</a></code> +- <code><a href="./src/resources/runners/runners.ts">RunnerRetrieveResponse</a></code> +- <code><a href="./src/resources/runners/runners.ts">RunnerUpdateResponse</a></code> +- <code><a href="./src/resources/runners/runners.ts">RunnerDeleteResponse</a></code> +- <code><a href="./src/resources/runners/runners.ts">RunnerCheckAuthenticationForHostResponse</a></code> +- <code><a href="./src/resources/runners/runners.ts">RunnerCreateRunnerTokenResponse</a></code> +- <code><a href="./src/resources/runners/runners.ts">RunnerParseContextURLResponse</a></code> + +Methods: + +- <code title="post /gitpod.v1.RunnerService/CreateRunner">client.runners.<a href="./src/resources/runners/runners.ts">create</a>({ ...params }) -> RunnerCreateResponse</code> +- <code title="post /gitpod.v1.RunnerService/GetRunner">client.runners.<a href="./src/resources/runners/runners.ts">retrieve</a>({ ...params }) -> RunnerRetrieveResponse</code> +- <code title="post /gitpod.v1.RunnerService/UpdateRunner">client.runners.<a href="./src/resources/runners/runners.ts">update</a>({ ...params }) -> unknown</code> +- <code title="post /gitpod.v1.RunnerService/ListRunners">client.runners.<a href="./src/resources/runners/runners.ts">list</a>({ ...params }) -> RunnersRunnersPage</code> +- <code title="post /gitpod.v1.RunnerService/DeleteRunner">client.runners.<a href="./src/resources/runners/runners.ts">delete</a>({ ...params }) -> unknown</code> +- <code title="post /gitpod.v1.RunnerService/CheckAuthenticationForHost">client.runners.<a href="./src/resources/runners/runners.ts">checkAuthenticationForHost</a>({ ...params }) -> RunnerCheckAuthenticationForHostResponse</code> +- <code title="post /gitpod.v1.RunnerService/CreateRunnerToken">client.runners.<a href="./src/resources/runners/runners.ts">createRunnerToken</a>({ ...params }) -> RunnerCreateRunnerTokenResponse</code> +- <code title="post /gitpod.v1.RunnerService/ParseContextURL">client.runners.<a href="./src/resources/runners/runners.ts">parseContextURL</a>({ ...params }) -> RunnerParseContextURLResponse</code> + +## Configurations + +Types: + +- <code><a href="./src/resources/runners/configurations/configurations.ts">EnvironmentClassValidationResult</a></code> +- <code><a href="./src/resources/runners/configurations/configurations.ts">FieldValidationError</a></code> +- <code><a href="./src/resources/runners/configurations/configurations.ts">ScmIntegrationValidationResult</a></code> +- <code><a href="./src/resources/runners/configurations/configurations.ts">ConfigurationValidateResponse</a></code> + +Methods: + +- <code title="post /gitpod.v1.RunnerConfigurationService/ValidateRunnerConfiguration">client.runners.configurations.<a href="./src/resources/runners/configurations/configurations.ts">validate</a>({ ...params }) -> ConfigurationValidateResponse</code> + +### EnvironmentClasses + +Types: + +- <code><a href="./src/resources/runners/configurations/environment-classes.ts">EnvironmentClassCreateResponse</a></code> +- <code><a href="./src/resources/runners/configurations/environment-classes.ts">EnvironmentClassRetrieveResponse</a></code> +- <code><a href="./src/resources/runners/configurations/environment-classes.ts">EnvironmentClassUpdateResponse</a></code> + +Methods: + +- <code title="post /gitpod.v1.RunnerConfigurationService/CreateEnvironmentClass">client.runners.configurations.environmentClasses.<a href="./src/resources/runners/configurations/environment-classes.ts">create</a>({ ...params }) -> EnvironmentClassCreateResponse</code> +- <code title="post /gitpod.v1.RunnerConfigurationService/GetEnvironmentClass">client.runners.configurations.environmentClasses.<a href="./src/resources/runners/configurations/environment-classes.ts">retrieve</a>({ ...params }) -> EnvironmentClassRetrieveResponse</code> +- <code title="post /gitpod.v1.RunnerConfigurationService/UpdateEnvironmentClass">client.runners.configurations.environmentClasses.<a href="./src/resources/runners/configurations/environment-classes.ts">update</a>({ ...params }) -> unknown</code> +- <code title="post /gitpod.v1.RunnerConfigurationService/ListEnvironmentClasses">client.runners.configurations.environmentClasses.<a href="./src/resources/runners/configurations/environment-classes.ts">list</a>({ ...params }) -> EnvironmentClassesEnvironmentClassesPage</code> + +### HostAuthenticationTokens + +Types: + +- <code><a href="./src/resources/runners/configurations/host-authentication-tokens.ts">HostAuthenticationToken</a></code> +- <code><a href="./src/resources/runners/configurations/host-authentication-tokens.ts">HostAuthenticationTokenSource</a></code> +- <code><a href="./src/resources/runners/configurations/host-authentication-tokens.ts">HostAuthenticationTokenCreateResponse</a></code> +- <code><a href="./src/resources/runners/configurations/host-authentication-tokens.ts">HostAuthenticationTokenRetrieveResponse</a></code> +- <code><a href="./src/resources/runners/configurations/host-authentication-tokens.ts">HostAuthenticationTokenUpdateResponse</a></code> +- <code><a href="./src/resources/runners/configurations/host-authentication-tokens.ts">HostAuthenticationTokenDeleteResponse</a></code> + +Methods: + +- <code title="post /gitpod.v1.RunnerConfigurationService/CreateHostAuthenticationToken">client.runners.configurations.hostAuthenticationTokens.<a href="./src/resources/runners/configurations/host-authentication-tokens.ts">create</a>({ ...params }) -> HostAuthenticationTokenCreateResponse</code> +- <code title="post /gitpod.v1.RunnerConfigurationService/GetHostAuthenticationToken">client.runners.configurations.hostAuthenticationTokens.<a href="./src/resources/runners/configurations/host-authentication-tokens.ts">retrieve</a>({ ...params }) -> HostAuthenticationTokenRetrieveResponse</code> +- <code title="post /gitpod.v1.RunnerConfigurationService/UpdateHostAuthenticationToken">client.runners.configurations.hostAuthenticationTokens.<a href="./src/resources/runners/configurations/host-authentication-tokens.ts">update</a>({ ...params }) -> unknown</code> +- <code title="post /gitpod.v1.RunnerConfigurationService/ListHostAuthenticationTokens">client.runners.configurations.hostAuthenticationTokens.<a href="./src/resources/runners/configurations/host-authentication-tokens.ts">list</a>({ ...params }) -> HostAuthenticationTokensTokensPage</code> +- <code title="post /gitpod.v1.RunnerConfigurationService/DeleteHostAuthenticationToken">client.runners.configurations.hostAuthenticationTokens.<a href="./src/resources/runners/configurations/host-authentication-tokens.ts">delete</a>({ ...params }) -> unknown</code> + +### Schema + +Types: + +- <code><a href="./src/resources/runners/configurations/schema.ts">RunnerConfigurationSchema</a></code> +- <code><a href="./src/resources/runners/configurations/schema.ts">SchemaRetrieveResponse</a></code> + +Methods: + +- <code title="post /gitpod.v1.RunnerConfigurationService/GetRunnerConfigurationSchema">client.runners.configurations.schema.<a href="./src/resources/runners/configurations/schema.ts">retrieve</a>({ ...params }) -> SchemaRetrieveResponse</code> + +### ScmIntegrations + +Types: + +- <code><a href="./src/resources/runners/configurations/scm-integrations.ts">ScmIntegration</a></code> +- <code><a href="./src/resources/runners/configurations/scm-integrations.ts">ScmIntegrationOAuthConfig</a></code> +- <code><a href="./src/resources/runners/configurations/scm-integrations.ts">ScmIntegrationCreateResponse</a></code> +- <code><a href="./src/resources/runners/configurations/scm-integrations.ts">ScmIntegrationRetrieveResponse</a></code> +- <code><a href="./src/resources/runners/configurations/scm-integrations.ts">ScmIntegrationUpdateResponse</a></code> +- <code><a href="./src/resources/runners/configurations/scm-integrations.ts">ScmIntegrationDeleteResponse</a></code> + +Methods: + +- <code title="post /gitpod.v1.RunnerConfigurationService/CreateSCMIntegration">client.runners.configurations.scmIntegrations.<a href="./src/resources/runners/configurations/scm-integrations.ts">create</a>({ ...params }) -> ScmIntegrationCreateResponse</code> +- <code title="post /gitpod.v1.RunnerConfigurationService/GetSCMIntegration">client.runners.configurations.scmIntegrations.<a href="./src/resources/runners/configurations/scm-integrations.ts">retrieve</a>({ ...params }) -> ScmIntegrationRetrieveResponse</code> +- <code title="post /gitpod.v1.RunnerConfigurationService/UpdateSCMIntegration">client.runners.configurations.scmIntegrations.<a href="./src/resources/runners/configurations/scm-integrations.ts">update</a>({ ...params }) -> unknown</code> +- <code title="post /gitpod.v1.RunnerConfigurationService/ListSCMIntegrations">client.runners.configurations.scmIntegrations.<a href="./src/resources/runners/configurations/scm-integrations.ts">list</a>({ ...params }) -> ScmIntegrationsIntegrationsPage</code> +- <code title="post /gitpod.v1.RunnerConfigurationService/DeleteSCMIntegration">client.runners.configurations.scmIntegrations.<a href="./src/resources/runners/configurations/scm-integrations.ts">delete</a>({ ...params }) -> unknown</code> + +## Policies + +Types: + +- <code><a href="./src/resources/runners/policies.ts">RunnerPolicy</a></code> +- <code><a href="./src/resources/runners/policies.ts">RunnerRole</a></code> +- <code><a href="./src/resources/runners/policies.ts">PolicyCreateResponse</a></code> +- <code><a href="./src/resources/runners/policies.ts">PolicyUpdateResponse</a></code> +- <code><a href="./src/resources/runners/policies.ts">PolicyDeleteResponse</a></code> + +Methods: + +- <code title="post /gitpod.v1.RunnerService/CreateRunnerPolicy">client.runners.policies.<a href="./src/resources/runners/policies.ts">create</a>({ ...params }) -> PolicyCreateResponse</code> +- <code title="post /gitpod.v1.RunnerService/UpdateRunnerPolicy">client.runners.policies.<a href="./src/resources/runners/policies.ts">update</a>({ ...params }) -> PolicyUpdateResponse</code> +- <code title="post /gitpod.v1.RunnerService/ListRunnerPolicies">client.runners.policies.<a href="./src/resources/runners/policies.ts">list</a>({ ...params }) -> RunnerPoliciesPoliciesPage</code> +- <code title="post /gitpod.v1.RunnerService/DeleteRunnerPolicy">client.runners.policies.<a href="./src/resources/runners/policies.ts">delete</a>({ ...params }) -> unknown</code> + +# Secrets + +Types: + +- <code><a href="./src/resources/secrets.ts">Secret</a></code> +- <code><a href="./src/resources/secrets.ts">SecretScope</a></code> +- <code><a href="./src/resources/secrets.ts">SecretCreateResponse</a></code> +- <code><a href="./src/resources/secrets.ts">SecretDeleteResponse</a></code> +- <code><a href="./src/resources/secrets.ts">SecretGetValueResponse</a></code> +- <code><a href="./src/resources/secrets.ts">SecretUpdateValueResponse</a></code> + +Methods: + +- <code title="post /gitpod.v1.SecretService/CreateSecret">client.secrets.<a href="./src/resources/secrets.ts">create</a>({ ...params }) -> SecretCreateResponse</code> +- <code title="post /gitpod.v1.SecretService/ListSecrets">client.secrets.<a href="./src/resources/secrets.ts">list</a>({ ...params }) -> SecretsSecretsPage</code> +- <code title="post /gitpod.v1.SecretService/DeleteSecret">client.secrets.<a href="./src/resources/secrets.ts">delete</a>({ ...params }) -> unknown</code> +- <code title="post /gitpod.v1.SecretService/GetSecretValue">client.secrets.<a href="./src/resources/secrets.ts">getValue</a>({ ...params }) -> SecretGetValueResponse</code> +- <code title="post /gitpod.v1.SecretService/UpdateSecretValue">client.secrets.<a href="./src/resources/secrets.ts">updateValue</a>({ ...params }) -> unknown</code> + +# Usage + +Types: + +- <code><a href="./src/resources/usage.ts">EnvironmentSession</a></code> + +Methods: + +- <code title="post /gitpod.v1.UsageService/ListEnvironmentSessions">client.usage.<a href="./src/resources/usage.ts">listEnvironmentSessions</a>({ ...params }) -> EnvironmentSessionsSessionsPage</code> + +# Users + +Types: + +- <code><a href="./src/resources/users/users.ts">User</a></code> +- <code><a href="./src/resources/users/users.ts">UserGetAuthenticatedUserResponse</a></code> +- <code><a href="./src/resources/users/users.ts">UserSetSuspendedResponse</a></code> + +Methods: + +- <code title="post /gitpod.v1.UserService/GetAuthenticatedUser">client.users.<a href="./src/resources/users/users.ts">getAuthenticatedUser</a>({ ...params }) -> UserGetAuthenticatedUserResponse</code> +- <code title="post /gitpod.v1.UserService/SetSuspended">client.users.<a href="./src/resources/users/users.ts">setSuspended</a>({ ...params }) -> unknown</code> + +## Dotfiles + +Types: + +- <code><a href="./src/resources/users/dotfiles.ts">DotfilesConfiguration</a></code> +- <code><a href="./src/resources/users/dotfiles.ts">DotfileGetResponse</a></code> +- <code><a href="./src/resources/users/dotfiles.ts">DotfileSetResponse</a></code> + +Methods: + +- <code title="post /gitpod.v1.UserService/GetDotfilesConfiguration">client.users.dotfiles.<a href="./src/resources/users/dotfiles.ts">get</a>({ ...params }) -> DotfileGetResponse</code> +- <code title="post /gitpod.v1.UserService/SetDotfilesConfiguration">client.users.dotfiles.<a href="./src/resources/users/dotfiles.ts">set</a>({ ...params }) -> unknown</code> + +## Pats + +Types: + +- <code><a href="./src/resources/users/pats.ts">PersonalAccessToken</a></code> +- <code><a href="./src/resources/users/pats.ts">PatDeleteResponse</a></code> +- <code><a href="./src/resources/users/pats.ts">PatGetResponse</a></code> + +Methods: + +- <code title="post /gitpod.v1.UserService/ListPersonalAccessTokens">client.users.pats.<a href="./src/resources/users/pats.ts">list</a>({ ...params }) -> PersonalAccessTokensPersonalAccessTokensPage</code> +- <code title="post /gitpod.v1.UserService/DeletePersonalAccessToken">client.users.pats.<a href="./src/resources/users/pats.ts">delete</a>({ ...params }) -> unknown</code> +- <code title="post /gitpod.v1.UserService/GetPersonalAccessToken">client.users.pats.<a href="./src/resources/users/pats.ts">get</a>({ ...params }) -> PatGetResponse</code> diff --git a/bin/check-release-environment b/bin/check-release-environment new file mode 100644 index 0000000..0d4280c --- /dev/null +++ b/bin/check-release-environment @@ -0,0 +1,22 @@ +#!/usr/bin/env bash + +errors=() + +if [ -z "${NPM_TOKEN}" ]; then + errors+=("The GITPOD_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 new file mode 100644 index 0000000..4c21181 --- /dev/null +++ b/bin/publish-npm @@ -0,0 +1,25 @@ +#!/usr/bin/env bash + +set -eux + +npm config set '//registry.npmjs.org/:_authToken' "$NPM_TOKEN" + +# Build the project +yarn build + +# Navigate to the dist directory +cd dist + +# Get the version from package.json +VERSION="$(node -p "require('./package.json').version")" + +# Extract the pre-release tag if it exists +if [[ "$VERSION" =~ -([a-zA-Z]+) ]]; then + # Extract the part before any dot in the pre-release identifier + TAG="${BASH_REMATCH[1]}" +else + TAG="latest" +fi + +# Publish with the appropriate tag +yarn publish --access public --tag "$TAG" diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000..bd8e0cb --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,42 @@ +// @ts-check +import tseslint from 'typescript-eslint'; +import unusedImports from 'eslint-plugin-unused-imports'; +import prettier from 'eslint-plugin-prettier'; + +export default tseslint.config( + { + languageOptions: { + parser: tseslint.parser, + parserOptions: { sourceType: 'module' }, + }, + files: ['**/*.ts', '**/*.mts', '**/*.cts', '**/*.js', '**/*.mjs', '**/*.cjs'], + ignores: ['dist/**'], + plugins: { + '@typescript-eslint': tseslint.plugin, + 'unused-imports': unusedImports, + prettier, + }, + rules: { + 'no-unused-vars': 'off', + 'prettier/prettier': 'error', + 'unused-imports/no-unused-imports': 'error', + 'no-restricted-imports': [ + 'error', + { + patterns: [ + { + regex: '^@gitpod/sdk(/.*)?', + message: 'Use a relative import, not a package import.', + }, + ], + }, + ], + }, + }, + { + files: ['tests/**', 'examples/**'], + rules: { + 'no-restricted-imports': 'off', + }, + }, +); diff --git a/examples/.keep b/examples/.keep new file mode 100644 index 0000000..0651c89 --- /dev/null +++ b/examples/.keep @@ -0,0 +1,4 @@ +File generated from our OpenAPI spec by Stainless. + +This directory can be used to store example files demonstrating usage of this SDK. +It is ignored by Stainless code generation and its content (other than this keep file) won't be touched. diff --git a/jest.config.ts b/jest.config.ts new file mode 100644 index 0000000..d185444 --- /dev/null +++ b/jest.config.ts @@ -0,0 +1,22 @@ +import type { JestConfigWithTsJest } from 'ts-jest'; + +const config: JestConfigWithTsJest = { + preset: 'ts-jest/presets/default-esm', + testEnvironment: 'node', + transform: { + '^.+\\.(t|j)sx?$': ['@swc/jest', { sourceMaps: 'inline' }], + }, + moduleNameMapper: { + '^@gitpod/sdk$': '<rootDir>/src/index.ts', + '^@gitpod/sdk/(.*)$': '<rootDir>/src/$1', + }, + modulePathIgnorePatterns: [ + '<rootDir>/ecosystem-tests/', + '<rootDir>/dist/', + '<rootDir>/deno/', + '<rootDir>/deno_tests/', + ], + testPathIgnorePatterns: ['scripts'], +}; + +export default config; diff --git a/package.json b/package.json new file mode 100644 index 0000000..a1541d7 --- /dev/null +++ b/package.json @@ -0,0 +1,76 @@ +{ + "name": "@gitpod/sdk", + "version": "0.5.0", + "description": "The official TypeScript library for the Gitpod API", + "author": "Gitpod <dev-feedback@gitpod.com>", + "types": "dist/index.d.ts", + "main": "dist/index.js", + "type": "commonjs", + "repository": "github:gitpod-io/gitpod-sdk-typescript", + "license": "Apache-2.0", + "packageManager": "yarn@1.22.22", + "files": [ + "**/*" + ], + "private": false, + "scripts": { + "test": "./scripts/test", + "build": "./scripts/build", + "prepublishOnly": "echo 'to publish, run yarn build && (cd dist; yarn publish)' && exit 1", + "format": "./scripts/format", + "prepare": "if ./scripts/utils/check-is-in-git-install.sh; then ./scripts/build && ./scripts/utils/git-swap.sh; fi", + "tsn": "ts-node -r tsconfig-paths/register", + "lint": "./scripts/lint", + "fix": "./scripts/format" + }, + "dependencies": {}, + "devDependencies": { + "@arethetypeswrong/cli": "^0.17.0", + "@swc/core": "^1.3.102", + "@swc/jest": "^0.2.29", + "@types/jest": "^29.4.0", + "@types/node": "^20.17.6", + "typescript-eslint": "8.31.1", + "@typescript-eslint/eslint-plugin": "8.31.1", + "@typescript-eslint/parser": "8.31.1", + "eslint": "^9.20.1", + "eslint-plugin-prettier": "^5.2.3", + "eslint-plugin-unused-imports": "^4.1.4", + "iconv-lite": "^0.6.3", + "jest": "^29.4.0", + "prettier": "^3.0.0", + "publint": "^0.2.12", + "ts-jest": "^29.1.0", + "ts-node": "^10.5.0", + "tsc-multi": "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.4/tsc-multi-1.1.4.tgz", + "tsconfig-paths": "^4.0.0", + "typescript": "5.8.3" + }, + "resolutions": { + "synckit": "0.8.8" + }, + "browser": { + "./internal/shims/getBuiltinModule.mjs": "./internal/shims/nullGetBuiltinModule.mjs", + "./internal/shims/getBuiltinModule.js": "./internal/shims/nullGetBuiltinModule.js" + }, + "imports": { + "@gitpod/sdk": ".", + "@gitpod/sdk/*": "./src/*" + }, + "exports": { + ".": { + "import": "./dist/index.mjs", + "require": "./dist/index.js" + }, + "./*.mjs": { + "default": "./dist/*.mjs" + }, + "./*.js": { + "default": "./dist/*.js" + }, + "./*": { + "import": "./dist/*.mjs", + "require": "./dist/*.js" + } + } +} diff --git a/release-please-config.json b/release-please-config.json new file mode 100644 index 0000000..1ebd0bd --- /dev/null +++ b/release-please-config.json @@ -0,0 +1,64 @@ +{ + "packages": { + ".": {} + }, + "$schema": "https://raw.githubusercontent.com/stainless-api/release-please/main/schemas/config.json", + "include-v-in-tag": true, + "include-component-in-tag": false, + "versioning": "prerelease", + "prerelease": true, + "bump-minor-pre-major": true, + "bump-patch-for-minor-pre-major": false, + "pull-request-header": "Automated Release PR", + "pull-request-title-pattern": "release: ${version}", + "changelog-sections": [ + { + "type": "feat", + "section": "Features" + }, + { + "type": "fix", + "section": "Bug Fixes" + }, + { + "type": "perf", + "section": "Performance Improvements" + }, + { + "type": "revert", + "section": "Reverts" + }, + { + "type": "chore", + "section": "Chores" + }, + { + "type": "docs", + "section": "Documentation" + }, + { + "type": "style", + "section": "Styles" + }, + { + "type": "refactor", + "section": "Refactors" + }, + { + "type": "test", + "section": "Tests", + "hidden": true + }, + { + "type": "build", + "section": "Build System" + }, + { + "type": "ci", + "section": "Continuous Integration", + "hidden": true + } + ], + "release-type": "node", + "extra-files": ["src/version.ts", "README.md"] +} diff --git a/scripts/bootstrap b/scripts/bootstrap new file mode 100755 index 0000000..0af58e2 --- /dev/null +++ b/scripts/bootstrap @@ -0,0 +1,18 @@ +#!/usr/bin/env bash + +set -e + +cd "$(dirname "$0")/.." + +if [ -f "Brewfile" ] && [ "$(uname -s)" = "Darwin" ] && [ "$SKIP_BREW" != "1" ]; then + brew bundle check >/dev/null 2>&1 || { + echo "==> Installing Homebrew dependencies…" + brew bundle + } +fi + +echo "==> Installing Node dependencies…" + +PACKAGE_MANAGER=$(command -v yarn >/dev/null 2>&1 && echo "yarn" || echo "npm") + +$PACKAGE_MANAGER install diff --git a/scripts/build b/scripts/build new file mode 100755 index 0000000..3323742 --- /dev/null +++ b/scripts/build @@ -0,0 +1,53 @@ +#!/usr/bin/env bash + +set -exuo pipefail + +cd "$(dirname "$0")/.." + +node scripts/utils/check-version.cjs + +# Build into dist and will publish the package from there, +# so that src/resources/foo.ts becomes <package root>/resources/foo.js +# This way importing from `"@gitpod/sdk/resources/foo"` works +# even with `"moduleResolution": "node"` + +rm -rf dist; mkdir dist +# Copy src to dist/src and build from dist/src into dist, so that +# the source map for index.js.map will refer to ./src/index.ts etc +cp -rp src README.md dist +for file in LICENSE CHANGELOG.md; do + if [ -e "${file}" ]; then cp "${file}" dist; fi +done +if [ -e "bin/cli" ]; then + mkdir -p dist/bin + cp -p "bin/cli" dist/bin/; +fi +if [ -e "bin/migration-config.json" ]; then + mkdir -p dist/bin + cp -p "bin/migration-config.json" dist/bin/; +fi +# this converts the export map paths for the dist directory +# and does a few other minor things +node scripts/utils/make-dist-package-json.cjs > dist/package.json + +# build to .js/.mjs/.d.ts files +npm exec tsc-multi +# we need to patch index.js so that `new module.exports()` works for cjs backwards +# compat. No way to get that from index.ts because it would cause compile errors +# when building .mjs +node scripts/utils/fix-index-exports.cjs +cp tsconfig.dist-src.json dist/src/tsconfig.json +cp src/internal/shim-types.d.ts dist/internal/shim-types.d.ts +cp src/internal/shim-types.d.ts dist/internal/shim-types.d.mts + +node scripts/utils/postprocess-files.cjs + +# make sure that nothing crashes when we require the output CJS or +# import the output ESM +(cd dist && node -e 'require("@gitpod/sdk")') +(cd dist && node -e 'import("@gitpod/sdk")' --input-type=module) + +if [ -e ./scripts/build-deno ] +then + ./scripts/build-deno +fi diff --git a/scripts/format b/scripts/format new file mode 100755 index 0000000..7a75640 --- /dev/null +++ b/scripts/format @@ -0,0 +1,12 @@ +#!/usr/bin/env bash + +set -e + +cd "$(dirname "$0")/.." + +echo "==> Running eslint --fix" +./node_modules/.bin/eslint --fix . + +echo "==> Running prettier --write" +# format things eslint didn't +./node_modules/.bin/prettier --write --cache --cache-strategy metadata . '!**/dist' '!**/*.ts' '!**/*.mts' '!**/*.cts' '!**/*.js' '!**/*.mjs' '!**/*.cjs' diff --git a/scripts/lint b/scripts/lint new file mode 100755 index 0000000..3ffb78a --- /dev/null +++ b/scripts/lint @@ -0,0 +1,21 @@ +#!/usr/bin/env bash + +set -e + +cd "$(dirname "$0")/.." + +echo "==> Running eslint" +./node_modules/.bin/eslint . + +echo "==> Building" +./scripts/build + +echo "==> Checking types" +./node_modules/typescript/bin/tsc + +echo "==> Running Are The Types Wrong?" +./node_modules/.bin/attw --pack dist -f json >.attw.json || true +node scripts/utils/attw-report.cjs + +echo "==> Running publint" +./node_modules/.bin/publint dist diff --git a/scripts/mock b/scripts/mock new file mode 100755 index 0000000..d2814ae --- /dev/null +++ b/scripts/mock @@ -0,0 +1,41 @@ +#!/usr/bin/env bash + +set -e + +cd "$(dirname "$0")/.." + +if [[ -n "$1" && "$1" != '--'* ]]; then + URL="$1" + shift +else + URL="$(grep 'openapi_spec_url' .stats.yml | cut -d' ' -f2)" +fi + +# Check if the URL is empty +if [ -z "$URL" ]; then + echo "Error: No OpenAPI spec path/url provided or found in .stats.yml" + exit 1 +fi + +echo "==> Starting mock server with URL ${URL}" + +# Run prism mock on the given spec +if [ "$1" == "--daemon" ]; then + npm exec --package=@stainless-api/prism-cli@5.8.5 -- prism mock "$URL" &> .prism.log & + + # Wait for server to come online + echo -n "Waiting for server" + while ! grep -q "✖ fatal\|Prism is listening" ".prism.log" ; do + echo -n "." + sleep 0.1 + done + + if grep -q "✖ fatal" ".prism.log"; then + cat .prism.log + exit 1 + fi + + echo +else + npm exec --package=@stainless-api/prism-cli@5.8.5 -- prism mock "$URL" +fi diff --git a/scripts/test b/scripts/test new file mode 100755 index 0000000..2049e31 --- /dev/null +++ b/scripts/test @@ -0,0 +1,56 @@ +#!/usr/bin/env bash + +set -e + +cd "$(dirname "$0")/.." + +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[0;33m' +NC='\033[0m' # No Color + +function prism_is_running() { + curl --silent "http://localhost:4010" >/dev/null 2>&1 +} + +kill_server_on_port() { + pids=$(lsof -t -i tcp:"$1" || echo "") + if [ "$pids" != "" ]; then + kill "$pids" + echo "Stopped $pids." + fi +} + +function is_overriding_api_base_url() { + [ -n "$TEST_API_BASE_URL" ] +} + +if ! is_overriding_api_base_url && ! prism_is_running ; then + # When we exit this script, make sure to kill the background mock server process + trap 'kill_server_on_port 4010' EXIT + + # Start the dev server + ./scripts/mock --daemon +fi + +if is_overriding_api_base_url ; then + echo -e "${GREEN}✔ Running tests against ${TEST_API_BASE_URL}${NC}" + echo +elif ! prism_is_running ; then + echo -e "${RED}ERROR:${NC} The test suite will not run without a mock Prism server" + echo -e "running against your OpenAPI spec." + echo + echo -e "To run the server, pass in the path or url of your OpenAPI" + echo -e "spec to the prism command:" + echo + echo -e " \$ ${YELLOW}npm exec --package=@stoplight/prism-cli@~5.3.2 -- prism mock path/to/your.openapi.yml${NC}" + echo + + exit 1 +else + echo -e "${GREEN}✔ Mock prism server is running with your OpenAPI spec${NC}" + echo +fi + +echo "==> Running tests" +./node_modules/.bin/jest "$@" diff --git a/scripts/utils/attw-report.cjs b/scripts/utils/attw-report.cjs new file mode 100644 index 0000000..b3477c0 --- /dev/null +++ b/scripts/utils/attw-report.cjs @@ -0,0 +1,24 @@ +const fs = require('fs'); +const problems = Object.values(JSON.parse(fs.readFileSync('.attw.json', 'utf-8')).problems) + .flat() + .filter( + (problem) => + !( + // This is intentional, if the user specifies .mjs they get ESM. + ( + (problem.kind === 'CJSResolvesToESM' && problem.entrypoint.endsWith('.mjs')) || + // This is intentional for backwards compat reasons. + (problem.kind === 'MissingExportEquals' && problem.implementationFileName.endsWith('/index.js')) || + // this is intentional, we deliberately attempt to import types that may not exist from parent node_modules + // folders to better support various runtimes without triggering automatic type acquisition. + (problem.kind === 'InternalResolutionError' && problem.moduleSpecifier.includes('node_modules')) + ) + ), + ); +fs.unlinkSync('.attw.json'); +if (problems.length) { + process.stdout.write('The types are wrong!\n' + JSON.stringify(problems, null, 2) + '\n'); + process.exitCode = 1; +} else { + process.stdout.write('Types ok!\n'); +} diff --git a/scripts/utils/check-is-in-git-install.sh b/scripts/utils/check-is-in-git-install.sh new file mode 100755 index 0000000..1354eb4 --- /dev/null +++ b/scripts/utils/check-is-in-git-install.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +# Check if you happen to call prepare for a repository that's already in node_modules. +[ "$(basename "$(dirname "$PWD")")" = 'node_modules' ] || +# The name of the containing directory that 'npm` uses, which looks like +# $HOME/.npm/_cacache/git-cloneXXXXXX +[ "$(basename "$(dirname "$PWD")")" = 'tmp' ] || +# The name of the containing directory that 'yarn` uses, which looks like +# $(yarn cache dir)/.tmp/XXXXX +[ "$(basename "$(dirname "$PWD")")" = '.tmp' ] diff --git a/scripts/utils/check-version.cjs b/scripts/utils/check-version.cjs new file mode 100644 index 0000000..86c56df --- /dev/null +++ b/scripts/utils/check-version.cjs @@ -0,0 +1,20 @@ +const fs = require('fs'); +const path = require('path'); + +const main = () => { + const pkg = require('../../package.json'); + const version = pkg['version']; + if (!version) throw 'The version property is not set in the package.json file'; + if (typeof version !== 'string') { + throw `Unexpected type for the package.json version field; got ${typeof version}, expected string`; + } + + const versionFile = path.resolve(__dirname, '..', '..', 'src', 'version.ts'); + const contents = fs.readFileSync(versionFile, 'utf8'); + const output = contents.replace(/(export const VERSION = ')(.*)(')/g, `$1${version}$3`); + fs.writeFileSync(versionFile, output); +}; + +if (require.main === module) { + main(); +} diff --git a/scripts/utils/fix-index-exports.cjs b/scripts/utils/fix-index-exports.cjs new file mode 100644 index 0000000..e5e10b3 --- /dev/null +++ b/scripts/utils/fix-index-exports.cjs @@ -0,0 +1,17 @@ +const fs = require('fs'); +const path = require('path'); + +const indexJs = + process.env['DIST_PATH'] ? + path.resolve(process.env['DIST_PATH'], 'index.js') + : path.resolve(__dirname, '..', '..', 'dist', 'index.js'); + +let before = fs.readFileSync(indexJs, 'utf8'); +let after = before.replace( + /^(\s*Object\.defineProperty\s*\(exports,\s*["']__esModule["'].+)$/m, + `exports = module.exports = function (...args) { + return new exports.default(...args) + } + $1`.replace(/^ /gm, ''), +); +fs.writeFileSync(indexJs, after, 'utf8'); diff --git a/scripts/utils/git-swap.sh b/scripts/utils/git-swap.sh new file mode 100755 index 0000000..79d1888 --- /dev/null +++ b/scripts/utils/git-swap.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash +set -exuo pipefail +# the package is published to NPM from ./dist +# we want the final file structure for git installs to match the npm installs, so we + +# delete everything except ./dist and ./node_modules +find . -maxdepth 1 -mindepth 1 ! -name 'dist' ! -name 'node_modules' -exec rm -rf '{}' + + +# move everything from ./dist to . +mv dist/* . + +# delete the now-empty ./dist +rmdir dist diff --git a/scripts/utils/make-dist-package-json.cjs b/scripts/utils/make-dist-package-json.cjs new file mode 100644 index 0000000..7c24f56 --- /dev/null +++ b/scripts/utils/make-dist-package-json.cjs @@ -0,0 +1,21 @@ +const pkgJson = require(process.env['PKG_JSON_PATH'] || '../../package.json'); + +function processExportMap(m) { + for (const key in m) { + const value = m[key]; + if (typeof value === 'string') m[key] = value.replace(/^\.\/dist\//, './'); + else processExportMap(value); + } +} +processExportMap(pkgJson.exports); + +for (const key of ['types', 'main', 'module']) { + if (typeof pkgJson[key] === 'string') pkgJson[key] = pkgJson[key].replace(/^(\.\/)?dist\//, './'); +} + +delete pkgJson.devDependencies; +delete pkgJson.scripts.prepack; +delete pkgJson.scripts.prepublishOnly; +delete pkgJson.scripts.prepare; + +console.log(JSON.stringify(pkgJson, null, 2)); diff --git a/scripts/utils/postprocess-files.cjs b/scripts/utils/postprocess-files.cjs new file mode 100644 index 0000000..deae575 --- /dev/null +++ b/scripts/utils/postprocess-files.cjs @@ -0,0 +1,94 @@ +// @ts-check +const fs = require('fs'); +const path = require('path'); + +const distDir = + process.env['DIST_PATH'] ? + path.resolve(process.env['DIST_PATH']) + : path.resolve(__dirname, '..', '..', 'dist'); + +async function* walk(dir) { + for await (const d of await fs.promises.opendir(dir)) { + const entry = path.join(dir, d.name); + if (d.isDirectory()) yield* walk(entry); + else if (d.isFile()) yield entry; + } +} + +async function postprocess() { + for await (const file of walk(distDir)) { + if (!/(\.d)?[cm]?ts$/.test(file)) continue; + + const code = await fs.promises.readFile(file, 'utf8'); + + // strip out lib="dom", types="node", and types="react" references; these + // are needed at build time, but would pollute the user's TS environment + const transformed = code.replace( + /^ *\/\/\/ *<reference +(lib="dom"|types="(node|react)").*?\n/gm, + // replace with same number of characters to avoid breaking source maps + (match) => ' '.repeat(match.length - 1) + '\n', + ); + + if (transformed !== code) { + console.error(`wrote ${path.relative(process.cwd(), file)}`); + await fs.promises.writeFile(file, transformed, 'utf8'); + } + } + + const newExports = { + '.': { + require: { + types: './index.d.ts', + default: './index.js', + }, + types: './index.d.mts', + default: './index.mjs', + }, + }; + + for (const entry of await fs.promises.readdir(distDir, { withFileTypes: true })) { + if (entry.isDirectory() && entry.name !== 'src' && entry.name !== 'internal' && entry.name !== 'bin') { + const subpath = './' + entry.name; + newExports[subpath + '/*.mjs'] = { + default: subpath + '/*.mjs', + }; + newExports[subpath + '/*.js'] = { + default: subpath + '/*.js', + }; + newExports[subpath + '/*'] = { + import: subpath + '/*.mjs', + require: subpath + '/*.js', + }; + } else if (entry.isFile() && /\.[cm]?js$/.test(entry.name)) { + const { name, ext } = path.parse(entry.name); + const subpathWithoutExt = './' + name; + const subpath = './' + entry.name; + newExports[subpathWithoutExt] ||= { import: undefined, require: undefined }; + const isModule = ext[1] === 'm'; + if (isModule) { + newExports[subpathWithoutExt].import = subpath; + } else { + newExports[subpathWithoutExt].require = subpath; + } + newExports[subpath] = { + default: subpath, + }; + } + } + await fs.promises.writeFile( + 'dist/package.json', + JSON.stringify( + Object.assign( + /** @type {Record<String, unknown>} */ ( + JSON.parse(await fs.promises.readFile('dist/package.json', 'utf-8')) + ), + { + exports: newExports, + }, + ), + null, + 2, + ), + ); +} +postprocess(); diff --git a/scripts/utils/upload-artifact.sh b/scripts/utils/upload-artifact.sh new file mode 100755 index 0000000..864a4c8 --- /dev/null +++ b/scripts/utils/upload-artifact.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash +set -exuo pipefail + +RESPONSE=$(curl -X POST "$URL" \ + -H "Authorization: Bearer $AUTH" \ + -H "Content-Type: application/json") + +SIGNED_URL=$(echo "$RESPONSE" | jq -r '.url') + +if [[ "$SIGNED_URL" == "null" ]]; then + echo -e "\033[31mFailed to get signed URL.\033[0m" + exit 1 +fi + +UPLOAD_RESPONSE=$(tar -cz dist | curl -v -X PUT \ + -H "Content-Type: application/gzip" \ + --data-binary @- "$SIGNED_URL" 2>&1) + +if echo "$UPLOAD_RESPONSE" | grep -q "HTTP/[0-9.]* 200"; then + echo -e "\033[32mUploaded build to Stainless storage.\033[0m" + echo -e "\033[32mInstallation: npm install 'https://pkg.stainless.com/s/gitpod-typescript/$SHA'\033[0m" +else + echo -e "\033[31mFailed to upload artifact.\033[0m" + exit 1 +fi diff --git a/src/api-promise.ts b/src/api-promise.ts new file mode 100644 index 0000000..8c775ee --- /dev/null +++ b/src/api-promise.ts @@ -0,0 +1,2 @@ +/** @deprecated Import from ./core/api-promise instead */ +export * from './core/api-promise'; diff --git a/src/client.ts b/src/client.ts new file mode 100644 index 0000000..d7e3523 --- /dev/null +++ b/src/client.ts @@ -0,0 +1,1243 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import type { RequestInit, RequestInfo, BodyInit } from './internal/builtin-types'; +import type { HTTPMethod, PromiseOrValue, MergedRequestInit, FinalizedRequestInit } from './internal/types'; +import { uuid4 } from './internal/utils/uuid'; +import { validatePositiveInteger, isAbsoluteURL, safeJSON } from './internal/utils/values'; +import { sleep } from './internal/utils/sleep'; +import { type Logger, type LogLevel, parseLogLevel } from './internal/utils/log'; +export type { Logger, LogLevel } from './internal/utils/log'; +import { castToError, isAbortError } from './internal/errors'; +import type { APIResponseProps } from './internal/parse'; +import { getPlatformHeaders } from './internal/detect-platform'; +import * as Shims from './internal/shims'; +import * as Opts from './internal/request-options'; +import { VERSION } from './version'; +import * as Errors from './core/error'; +import * as Pagination from './core/pagination'; +import { + AbstractPage, + type DomainVerificationsPageParams, + DomainVerificationsPageResponse, + type EditorsPageParams, + EditorsPageResponse, + type EntriesPageParams, + EntriesPageResponse, + type EnvironmentClassesPageParams, + EnvironmentClassesPageResponse, + type EnvironmentsPageParams, + EnvironmentsPageResponse, + type GroupsPageParams, + GroupsPageResponse, + type IntegrationsPageParams, + IntegrationsPageResponse, + type LoginProvidersPageParams, + LoginProvidersPageResponse, + type MembersPageParams, + MembersPageResponse, + type PersonalAccessTokensPageParams, + PersonalAccessTokensPageResponse, + type PoliciesPageParams, + PoliciesPageResponse, + type ProjectsPageParams, + ProjectsPageResponse, + type RunnersPageParams, + RunnersPageResponse, + type SSOConfigurationsPageParams, + SSOConfigurationsPageResponse, + type SecretsPageParams, + SecretsPageResponse, + type ServicesPageParams, + ServicesPageResponse, + type SessionsPageParams, + SessionsPageResponse, + type TaskExecutionsPageParams, + TaskExecutionsPageResponse, + type TasksPageParams, + TasksPageResponse, + type TokensPageParams, + TokensPageResponse, +} from './core/pagination'; +import * as Uploads from './core/uploads'; +import * as API from './resources/index'; +import { APIPromise } from './core/api-promise'; +import { type Fetch } from './internal/builtin-types'; +import { HeadersLike, NullableHeaders, buildHeaders } from './internal/headers'; +import { FinalRequestOptions, RequestOptions } from './internal/request-options'; +import { + Account, + AccountDeleteParams, + AccountDeleteResponse, + AccountGetSSOLoginURLParams, + AccountGetSSOLoginURLResponse, + AccountListLoginProvidersParams, + AccountMembership, + AccountRetrieveParams, + AccountRetrieveResponse, + Accounts, + JoinableOrganization, + LoginProvider, + LoginProvidersLoginProvidersPage, +} from './resources/accounts'; +import { + Editor, + EditorListParams, + EditorResolveURLParams, + EditorResolveURLResponse, + EditorRetrieveParams, + EditorRetrieveResponse, + Editors, + EditorsEditorsPage, +} from './resources/editors'; +import { + EventListParams, + EventListResponse, + EventListResponsesEntriesPage, + EventWatchParams, + EventWatchResponse, + Events, + ResourceOperation, + ResourceType, +} from './resources/events'; +import { Group, GroupListParams, Groups, GroupsGroupsPage } from './resources/groups'; +import { + IDTokenVersion, + Identity, + IdentityExchangeTokenParams, + IdentityExchangeTokenResponse, + IdentityGetAuthenticatedIdentityParams, + IdentityGetAuthenticatedIdentityResponse, + IdentityGetIDTokenParams, + IdentityGetIDTokenResponse, +} from './resources/identity'; +import { + Secret, + SecretCreateParams, + SecretCreateResponse, + SecretDeleteParams, + SecretDeleteResponse, + SecretGetValueParams, + SecretGetValueResponse, + SecretListParams, + SecretScope, + SecretUpdateValueParams, + SecretUpdateValueResponse, + Secrets, + SecretsSecretsPage, +} from './resources/secrets'; +import { + EnvironmentSession, + EnvironmentSessionsSessionsPage, + Usage, + UsageListEnvironmentSessionsParams, +} from './resources/usage'; +import { readEnv } from './internal/utils/env'; +import { formatRequestDetails, loggerFor } from './internal/utils/log'; +import { isEmptyObj } from './internal/utils/values'; +import { + AdmissionLevel, + Environment, + EnvironmentActivitySignal, + EnvironmentCreateEnvironmentTokenParams, + EnvironmentCreateEnvironmentTokenResponse, + EnvironmentCreateFromProjectParams, + EnvironmentCreateFromProjectResponse, + EnvironmentCreateLogsTokenParams, + EnvironmentCreateLogsTokenResponse, + EnvironmentCreateParams, + EnvironmentCreateResponse, + EnvironmentDeleteParams, + EnvironmentDeleteResponse, + EnvironmentListParams, + EnvironmentMarkActiveParams, + EnvironmentMarkActiveResponse, + EnvironmentMetadata, + EnvironmentPhase, + EnvironmentRetrieveParams, + EnvironmentRetrieveResponse, + EnvironmentSpec, + EnvironmentStartParams, + EnvironmentStartResponse, + EnvironmentStatus, + EnvironmentStopParams, + EnvironmentStopResponse, + EnvironmentUpdateParams, + EnvironmentUpdateResponse, + Environments, + EnvironmentsEnvironmentsPage, +} from './resources/environments/environments'; +import { + InviteDomains, + Organization, + OrganizationCreateParams, + OrganizationCreateResponse, + OrganizationDeleteParams, + OrganizationDeleteResponse, + OrganizationJoinParams, + OrganizationJoinResponse, + OrganizationLeaveParams, + OrganizationLeaveResponse, + OrganizationListMembersParams, + OrganizationMember, + OrganizationMembersMembersPage, + OrganizationRetrieveParams, + OrganizationRetrieveResponse, + OrganizationSetRoleParams, + OrganizationSetRoleResponse, + OrganizationTier, + OrganizationUpdateParams, + OrganizationUpdateResponse, + Organizations, +} from './resources/organizations/organizations'; +import { + EnvironmentInitializer, + Project, + ProjectCreateFromEnvironmentParams, + ProjectCreateFromEnvironmentResponse, + ProjectCreateParams, + ProjectCreateResponse, + ProjectDeleteParams, + ProjectDeleteResponse, + ProjectEnvironmentClass, + ProjectListParams, + ProjectMetadata, + ProjectRetrieveParams, + ProjectRetrieveResponse, + ProjectUpdateParams, + ProjectUpdateResponse, + Projects, + ProjectsProjectsPage, +} from './resources/projects/projects'; +import { + LogLevel, + MetricsConfiguration, + Runner, + RunnerCapability, + RunnerCheckAuthenticationForHostParams, + RunnerCheckAuthenticationForHostResponse, + RunnerConfiguration, + RunnerCreateParams, + RunnerCreateResponse, + RunnerCreateRunnerTokenParams, + RunnerCreateRunnerTokenResponse, + RunnerDeleteParams, + RunnerDeleteResponse, + RunnerKind, + RunnerListParams, + RunnerParseContextURLParams, + RunnerParseContextURLResponse, + RunnerPhase, + RunnerProvider, + RunnerReleaseChannel, + RunnerRetrieveParams, + RunnerRetrieveResponse, + RunnerSpec, + RunnerStatus, + RunnerUpdateParams, + RunnerUpdateResponse, + Runners, + RunnersRunnersPage, +} from './resources/runners/runners'; +import { + User, + UserGetAuthenticatedUserParams, + UserGetAuthenticatedUserResponse, + UserSetSuspendedParams, + UserSetSuspendedResponse, + Users, +} from './resources/users/users'; + +export interface ClientOptions { + /** + * Defaults to process.env['GITPOD_API_KEY']. + */ + bearerToken?: string | undefined; + + /** + * Override the default base URL for the API, e.g., "https://api.example.com/v2/" + * + * Defaults to process.env['GITPOD_BASE_URL']. + */ + baseURL?: string | null | undefined; + + /** + * The maximum amount of time (in milliseconds) that the client should wait for a response + * from the server before timing out a single request. + * + * Note that request timeouts are retried by default, so in a worst-case scenario you may wait + * much longer than this timeout before the promise succeeds or fails. + */ + timeout?: number | undefined; + /** + * Additional `RequestInit` options to be passed to `fetch` calls. + * Properties will be overridden by per-request `fetchOptions`. + */ + fetchOptions?: MergedRequestInit | undefined; + + /** + * Specify a custom `fetch` function implementation. + * + * If not provided, we expect that `fetch` is defined globally. + */ + fetch?: Fetch | undefined; + + /** + * The maximum number of times that the client will retry a request in case of a + * temporary failure, like a network error or a 5XX error from the server. + * + * @default 2 + */ + maxRetries?: number | undefined; + + /** + * Default headers to include with every request to the API. + * + * These can be removed in individual requests by explicitly setting the + * header to `null` in request options. + */ + defaultHeaders?: HeadersLike | undefined; + + /** + * Default query parameters to include with every request to the API. + * + * These can be removed in individual requests by explicitly setting the + * param to `undefined` in request options. + */ + defaultQuery?: Record<string, string | undefined> | undefined; + + /** + * Set the log level. + * + * Defaults to process.env['GITPOD_LOG'] or 'warn' if it isn't set. + */ + logLevel?: LogLevel | undefined; + + /** + * Set the logger. + * + * Defaults to globalThis.console. + */ + logger?: Logger | undefined; +} + +/** + * API Client for interfacing with the Gitpod API. + */ +export class Gitpod { + bearerToken: string; + + baseURL: string; + maxRetries: number; + timeout: number; + logger: Logger | undefined; + logLevel: LogLevel | undefined; + fetchOptions: MergedRequestInit | undefined; + + private fetch: Fetch; + #encoder: Opts.RequestEncoder; + protected idempotencyHeader?: string; + private _options: ClientOptions; + + /** + * API Client for interfacing with the Gitpod API. + * + * @param {string | undefined} [opts.bearerToken=process.env['GITPOD_API_KEY'] ?? undefined] + * @param {string} [opts.baseURL=process.env['GITPOD_BASE_URL'] ?? https://app.gitpod.io/api] - Override the default base URL for the API. + * @param {number} [opts.timeout=1 minute] - The maximum amount of time (in milliseconds) the client will wait for a response before timing out. + * @param {MergedRequestInit} [opts.fetchOptions] - Additional `RequestInit` options to be passed to `fetch` calls. + * @param {Fetch} [opts.fetch] - Specify a custom `fetch` function implementation. + * @param {number} [opts.maxRetries=2] - The maximum number of times the client will retry a request. + * @param {HeadersLike} opts.defaultHeaders - Default headers to include with every request to the API. + * @param {Record<string, string | undefined>} opts.defaultQuery - Default query parameters to include with every request to the API. + */ + constructor({ + baseURL = readEnv('GITPOD_BASE_URL'), + bearerToken = readEnv('GITPOD_API_KEY'), + ...opts + }: ClientOptions = {}) { + if (bearerToken === undefined) { + throw new Errors.GitpodError( + "The GITPOD_API_KEY environment variable is missing or empty; either provide it, or instantiate the Gitpod client with an bearerToken option, like new Gitpod({ bearerToken: 'My Bearer Token' }).", + ); + } + + const options: ClientOptions = { + bearerToken, + ...opts, + baseURL: baseURL || `https://app.gitpod.io/api`, + }; + + this.baseURL = options.baseURL!; + this.timeout = options.timeout ?? Gitpod.DEFAULT_TIMEOUT /* 1 minute */; + this.logger = options.logger ?? console; + const defaultLogLevel = 'warn'; + // Set default logLevel early so that we can log a warning in parseLogLevel. + this.logLevel = defaultLogLevel; + this.logLevel = + parseLogLevel(options.logLevel, 'ClientOptions.logLevel', this) ?? + parseLogLevel(readEnv('GITPOD_LOG'), "process.env['GITPOD_LOG']", this) ?? + defaultLogLevel; + this.fetchOptions = options.fetchOptions; + this.maxRetries = options.maxRetries ?? 2; + this.fetch = options.fetch ?? Shims.getDefaultFetch(); + this.#encoder = Opts.FallbackEncoder; + + this._options = options; + + this.bearerToken = bearerToken; + } + + protected defaultQuery(): Record<string, string | undefined> | undefined { + return this._options.defaultQuery; + } + + protected validateHeaders({ values, nulls }: NullableHeaders) { + return; + } + + protected authHeaders(opts: FinalRequestOptions): NullableHeaders | undefined { + return buildHeaders([{ Authorization: `Bearer ${this.bearerToken}` }]); + } + + /** + * Basic re-implementation of `qs.stringify` for primitive types. + */ + protected stringifyQuery(query: Record<string, unknown>): 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.GitpodError( + `Cannot stringify type ${typeof value}; Expected string, number, boolean, or null. If you need to pass nested query parameters, you can manually encode them, e.g. { query: { 'foo[key1]': value1, 'foo[key2]': value2 } }, and please open a GitHub issue requesting better support for your use case.`, + ); + }) + .join('&'); + } + + private getUserAgent(): string { + return `${this.constructor.name}/JS ${VERSION}`; + } + + protected defaultIdempotencyKey(): string { + return `stainless-node-retry-${uuid4()}`; + } + + protected makeStatusError( + status: number, + error: Object, + message: string | undefined, + headers: Headers, + ): Errors.APIError { + return Errors.APIError.generate(status, error, message, headers); + } + + buildURL(path: string, query: Record<string, unknown> | null | undefined): string { + const url = + isAbsoluteURL(path) ? + new URL(path) + : new URL(this.baseURL + (this.baseURL.endsWith('/') && path.startsWith('/') ? path.slice(1) : path)); + + const defaultQuery = this.defaultQuery(); + if (!isEmptyObj(defaultQuery)) { + query = { ...defaultQuery, ...query }; + } + + if (typeof query === 'object' && query && !Array.isArray(query)) { + url.search = this.stringifyQuery(query as Record<string, unknown>); + } + + return url.toString(); + } + + /** + * Used as a callback for mutating the given `FinalRequestOptions` object. + */ + protected async prepareOptions(options: FinalRequestOptions): Promise<void> {} + + /** + * Used as a callback for mutating the given `RequestInit` object. + * + * This is useful for cases where you want to add certain headers based off of + * the request properties, e.g. `method` or `url`. + */ + protected async prepareRequest( + request: RequestInit, + { url, options }: { url: string; options: FinalRequestOptions }, + ): Promise<void> {} + + get<Rsp>(path: string, opts?: PromiseOrValue<RequestOptions>): APIPromise<Rsp> { + return this.methodRequest('get', path, opts); + } + + post<Rsp>(path: string, opts?: PromiseOrValue<RequestOptions>): APIPromise<Rsp> { + return this.methodRequest('post', path, opts); + } + + patch<Rsp>(path: string, opts?: PromiseOrValue<RequestOptions>): APIPromise<Rsp> { + return this.methodRequest('patch', path, opts); + } + + put<Rsp>(path: string, opts?: PromiseOrValue<RequestOptions>): APIPromise<Rsp> { + return this.methodRequest('put', path, opts); + } + + delete<Rsp>(path: string, opts?: PromiseOrValue<RequestOptions>): APIPromise<Rsp> { + return this.methodRequest('delete', path, opts); + } + + private methodRequest<Rsp>( + method: HTTPMethod, + path: string, + opts?: PromiseOrValue<RequestOptions>, + ): APIPromise<Rsp> { + return this.request( + Promise.resolve(opts).then((opts) => { + return { method, path, ...opts }; + }), + ); + } + + request<Rsp>( + options: PromiseOrValue<FinalRequestOptions>, + remainingRetries: number | null = null, + ): APIPromise<Rsp> { + return new APIPromise(this, this.makeRequest(options, remainingRetries, undefined)); + } + + private async makeRequest( + optionsInput: PromiseOrValue<FinalRequestOptions>, + retriesRemaining: number | null, + retryOfRequestLogID: string | undefined, + ): Promise<APIResponseProps> { + const options = await optionsInput; + const maxRetries = options.maxRetries ?? this.maxRetries; + if (retriesRemaining == null) { + retriesRemaining = maxRetries; + } + + await this.prepareOptions(options); + + const { req, url, timeout } = this.buildRequest(options, { retryCount: maxRetries - retriesRemaining }); + + await this.prepareRequest(req, { url, options }); + + /** Not an API request ID, just for correlating local log entries. */ + const requestLogID = 'log_' + ((Math.random() * (1 << 24)) | 0).toString(16).padStart(6, '0'); + const retryLogStr = retryOfRequestLogID === undefined ? '' : `, retryOf: ${retryOfRequestLogID}`; + const startTime = Date.now(); + + loggerFor(this).debug( + `[${requestLogID}] sending request`, + formatRequestDetails({ + retryOfRequestLogID, + method: options.method, + url, + options, + headers: req.headers, + }), + ); + + if (options.signal?.aborted) { + throw new Errors.APIUserAbortError(); + } + + const controller = new AbortController(); + const response = await this.fetchWithTimeout(url, req, timeout, controller).catch(castToError); + const headersTime = Date.now(); + + if (response instanceof Error) { + const retryMessage = `retrying, ${retriesRemaining} attempts remaining`; + if (options.signal?.aborted) { + throw new Errors.APIUserAbortError(); + } + // detect native connection timeout errors + // deno throws "TypeError: error sending request for url (https://example/): client error (Connect): tcp connect error: Operation timed out (os error 60): Operation timed out (os error 60)" + // undici throws "TypeError: fetch failed" with cause "ConnectTimeoutError: Connect Timeout Error (attempted address: example:443, timeout: 1ms)" + // others do not provide enough information to distinguish timeouts from other connection errors + const isTimeout = + isAbortError(response) || + /timed? ?out/i.test(String(response) + ('cause' in response ? String(response.cause) : '')); + if (retriesRemaining) { + loggerFor(this).info( + `[${requestLogID}] connection ${isTimeout ? 'timed out' : 'failed'} - ${retryMessage}`, + ); + loggerFor(this).debug( + `[${requestLogID}] connection ${isTimeout ? 'timed out' : 'failed'} (${retryMessage})`, + formatRequestDetails({ + retryOfRequestLogID, + url, + durationMs: headersTime - startTime, + message: response.message, + }), + ); + return this.retryRequest(options, retriesRemaining, retryOfRequestLogID ?? requestLogID); + } + loggerFor(this).info( + `[${requestLogID}] connection ${isTimeout ? 'timed out' : 'failed'} - error; no more retries left`, + ); + loggerFor(this).debug( + `[${requestLogID}] connection ${isTimeout ? 'timed out' : 'failed'} (error; no more retries left)`, + formatRequestDetails({ + retryOfRequestLogID, + url, + durationMs: headersTime - startTime, + message: response.message, + }), + ); + if (isTimeout) { + throw new Errors.APIConnectionTimeoutError(); + } + throw new Errors.APIConnectionError({ cause: response }); + } + + const responseInfo = `[${requestLogID}${retryLogStr}] ${req.method} ${url} ${ + response.ok ? 'succeeded' : 'failed' + } with status ${response.status} in ${headersTime - startTime}ms`; + + if (!response.ok) { + const shouldRetry = this.shouldRetry(response); + if (retriesRemaining && shouldRetry) { + const retryMessage = `retrying, ${retriesRemaining} attempts remaining`; + + // We don't need the body of this response. + await Shims.CancelReadableStream(response.body); + loggerFor(this).info(`${responseInfo} - ${retryMessage}`); + loggerFor(this).debug( + `[${requestLogID}] response error (${retryMessage})`, + formatRequestDetails({ + retryOfRequestLogID, + url: response.url, + status: response.status, + headers: response.headers, + durationMs: headersTime - startTime, + }), + ); + return this.retryRequest( + options, + retriesRemaining, + retryOfRequestLogID ?? requestLogID, + response.headers, + ); + } + + const retryMessage = shouldRetry ? `error; no more retries left` : `error; not retryable`; + + loggerFor(this).info(`${responseInfo} - ${retryMessage}`); + + const errText = await response.text().catch((err: any) => castToError(err).message); + const errJSON = safeJSON(errText); + const errMessage = errJSON ? undefined : errText; + + loggerFor(this).debug( + `[${requestLogID}] response error (${retryMessage})`, + formatRequestDetails({ + retryOfRequestLogID, + url: response.url, + status: response.status, + headers: response.headers, + message: errMessage, + durationMs: Date.now() - startTime, + }), + ); + + const err = this.makeStatusError(response.status, errJSON, errMessage, response.headers); + throw err; + } + + loggerFor(this).info(responseInfo); + loggerFor(this).debug( + `[${requestLogID}] response start`, + formatRequestDetails({ + retryOfRequestLogID, + url: response.url, + status: response.status, + headers: response.headers, + durationMs: headersTime - startTime, + }), + ); + + return { response, options, controller, requestLogID, retryOfRequestLogID, startTime }; + } + + getAPIList<Item, PageClass extends Pagination.AbstractPage<Item> = Pagination.AbstractPage<Item>>( + path: string, + Page: new (...args: any[]) => PageClass, + opts?: RequestOptions, + ): Pagination.PagePromise<PageClass, Item> { + return this.requestAPIList(Page, { method: 'get', path, ...opts }); + } + + requestAPIList< + Item = unknown, + PageClass extends Pagination.AbstractPage<Item> = Pagination.AbstractPage<Item>, + >( + Page: new (...args: ConstructorParameters<typeof Pagination.AbstractPage>) => PageClass, + options: FinalRequestOptions, + ): Pagination.PagePromise<PageClass, Item> { + const request = this.makeRequest(options, null, undefined); + return new Pagination.PagePromise<PageClass, Item>(this as any as Gitpod, request, Page); + } + + async fetchWithTimeout( + url: RequestInfo, + init: RequestInit | undefined, + ms: number, + controller: AbortController, + ): Promise<Response> { + const { signal, method, ...options } = init || {}; + if (signal) signal.addEventListener('abort', () => controller.abort()); + + const timeout = setTimeout(() => controller.abort(), ms); + + const isReadableBody = + ((globalThis as any).ReadableStream && options.body instanceof (globalThis as any).ReadableStream) || + (typeof options.body === 'object' && options.body !== null && Symbol.asyncIterator in options.body); + + const fetchOptions: RequestInit = { + signal: controller.signal as any, + ...(isReadableBody ? { duplex: 'half' } : {}), + method: 'GET', + ...options, + }; + if (method) { + // Custom methods like 'patch' need to be uppercased + // See https://github.com/nodejs/undici/issues/2294 + fetchOptions.method = method.toUpperCase(); + } + + try { + // use undefined this binding; fetch errors if bound to something else in browser/cloudflare + return await this.fetch.call(undefined, url, fetchOptions); + } finally { + clearTimeout(timeout); + } + } + + private shouldRetry(response: Response): boolean { + // Note this is not a standard header. + const shouldRetryHeader = response.headers.get('x-should-retry'); + + // If the server explicitly says whether or not to retry, obey. + if (shouldRetryHeader === 'true') return true; + if (shouldRetryHeader === 'false') return false; + + // Retry on request timeouts. + if (response.status === 408) return true; + + // Retry on lock timeouts. + if (response.status === 409) return true; + + // Retry on rate limits. + if (response.status === 429) return true; + + // Retry internal errors. + if (response.status >= 500) return true; + + return false; + } + + private async retryRequest( + options: FinalRequestOptions, + retriesRemaining: number, + requestLogID: string, + responseHeaders?: Headers | undefined, + ): Promise<APIResponseProps> { + let timeoutMillis: number | undefined; + + // Note the `retry-after-ms` header may not be standard, but is a good idea and we'd like proactive support for it. + const retryAfterMillisHeader = responseHeaders?.get('retry-after-ms'); + if (retryAfterMillisHeader) { + const timeoutMs = parseFloat(retryAfterMillisHeader); + if (!Number.isNaN(timeoutMs)) { + timeoutMillis = timeoutMs; + } + } + + // About the Retry-After header: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Retry-After + const retryAfterHeader = responseHeaders?.get('retry-after'); + if (retryAfterHeader && !timeoutMillis) { + const timeoutSeconds = parseFloat(retryAfterHeader); + if (!Number.isNaN(timeoutSeconds)) { + timeoutMillis = timeoutSeconds * 1000; + } else { + timeoutMillis = Date.parse(retryAfterHeader) - Date.now(); + } + } + + // If the API asks us to wait a certain amount of time (and it's a reasonable amount), + // just do what it says, but otherwise calculate a default + if (!(timeoutMillis && 0 <= timeoutMillis && timeoutMillis < 60 * 1000)) { + const maxRetries = options.maxRetries ?? this.maxRetries; + timeoutMillis = this.calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries); + } + await sleep(timeoutMillis); + + return this.makeRequest(options, retriesRemaining - 1, requestLogID); + } + + private calculateDefaultRetryTimeoutMillis(retriesRemaining: number, maxRetries: number): number { + const initialRetryDelay = 0.5; + const maxRetryDelay = 8.0; + + const numRetries = maxRetries - retriesRemaining; + + // Apply exponential backoff, but not more than the max. + const sleepSeconds = Math.min(initialRetryDelay * Math.pow(2, numRetries), maxRetryDelay); + + // Apply some jitter, take up to at most 25 percent of the retry time. + const jitter = 1 - Math.random() * 0.25; + + return sleepSeconds * jitter * 1000; + } + + buildRequest( + inputOptions: FinalRequestOptions, + { retryCount = 0 }: { retryCount?: number } = {}, + ): { req: FinalizedRequestInit; url: string; timeout: number } { + const options = { ...inputOptions }; + const { method, path, query } = options; + + const url = this.buildURL(path!, query as Record<string, unknown>); + if ('timeout' in options) validatePositiveInteger('timeout', options.timeout); + options.timeout = options.timeout ?? this.timeout; + const { bodyHeaders, body } = this.buildBody({ options }); + const reqHeaders = this.buildHeaders({ options: inputOptions, method, bodyHeaders, retryCount }); + + const req: FinalizedRequestInit = { + method, + headers: reqHeaders, + ...(options.signal && { signal: options.signal }), + ...((globalThis as any).ReadableStream && + body instanceof (globalThis as any).ReadableStream && { duplex: 'half' }), + ...(body && { body }), + ...((this.fetchOptions as any) ?? {}), + ...((options.fetchOptions as any) ?? {}), + }; + + return { req, url, timeout: options.timeout }; + } + + private buildHeaders({ + options, + method, + bodyHeaders, + retryCount, + }: { + options: FinalRequestOptions; + method: HTTPMethod; + bodyHeaders: HeadersLike; + retryCount: number; + }): Headers { + let idempotencyHeaders: HeadersLike = {}; + if (this.idempotencyHeader && method !== 'get') { + if (!options.idempotencyKey) options.idempotencyKey = this.defaultIdempotencyKey(); + idempotencyHeaders[this.idempotencyHeader] = options.idempotencyKey; + } + + const headers = buildHeaders([ + idempotencyHeaders, + { + Accept: 'application/json', + 'User-Agent': this.getUserAgent(), + 'X-Stainless-Retry-Count': String(retryCount), + ...(options.timeout ? { 'X-Stainless-Timeout': String(Math.trunc(options.timeout / 1000)) } : {}), + ...getPlatformHeaders(), + }, + this.authHeaders(options), + this._options.defaultHeaders, + bodyHeaders, + options.headers, + ]); + + this.validateHeaders(headers); + + return headers.values; + } + + private buildBody({ options: { body, headers: rawHeaders } }: { options: FinalRequestOptions }): { + bodyHeaders: HeadersLike; + body: BodyInit | undefined; + } { + if (!body) { + return { bodyHeaders: undefined, body: undefined }; + } + const headers = buildHeaders([rawHeaders]); + if ( + // Pass raw type verbatim + ArrayBuffer.isView(body) || + body instanceof ArrayBuffer || + body instanceof DataView || + (typeof body === 'string' && + // Preserve legacy string encoding behavior for now + headers.values.has('content-type')) || + // `Blob` is superset of `File` + body instanceof Blob || + // `FormData` -> `multipart/form-data` + body instanceof FormData || + // `URLSearchParams` -> `application/x-www-form-urlencoded` + body instanceof URLSearchParams || + // Send chunked stream (each chunk has own `length`) + ((globalThis as any).ReadableStream && body instanceof (globalThis as any).ReadableStream) + ) { + return { bodyHeaders: undefined, body: body as BodyInit }; + } else if ( + typeof body === 'object' && + (Symbol.asyncIterator in body || + (Symbol.iterator in body && 'next' in body && typeof body.next === 'function')) + ) { + return { bodyHeaders: undefined, body: Shims.ReadableStreamFrom(body as AsyncIterable<Uint8Array>) }; + } else { + return this.#encoder({ body, headers }); + } + } + + static Gitpod = this; + static DEFAULT_TIMEOUT = 60000; // 1 minute + + static GitpodError = Errors.GitpodError; + static APIError = Errors.APIError; + static APIConnectionError = Errors.APIConnectionError; + static APIConnectionTimeoutError = Errors.APIConnectionTimeoutError; + static APIUserAbortError = Errors.APIUserAbortError; + static NotFoundError = Errors.NotFoundError; + static ConflictError = Errors.ConflictError; + static RateLimitError = Errors.RateLimitError; + static BadRequestError = Errors.BadRequestError; + static AuthenticationError = Errors.AuthenticationError; + static InternalServerError = Errors.InternalServerError; + static PermissionDeniedError = Errors.PermissionDeniedError; + static UnprocessableEntityError = Errors.UnprocessableEntityError; + + static toFile = Uploads.toFile; + + accounts: API.Accounts = new API.Accounts(this); + editors: API.Editors = new API.Editors(this); + environments: API.Environments = new API.Environments(this); + events: API.Events = new API.Events(this); + groups: API.Groups = new API.Groups(this); + identity: API.Identity = new API.Identity(this); + organizations: API.Organizations = new API.Organizations(this); + projects: API.Projects = new API.Projects(this); + runners: API.Runners = new API.Runners(this); + secrets: API.Secrets = new API.Secrets(this); + usage: API.Usage = new API.Usage(this); + users: API.Users = new API.Users(this); +} +Gitpod.Accounts = Accounts; +Gitpod.Editors = Editors; +Gitpod.Environments = Environments; +Gitpod.Events = Events; +Gitpod.Groups = Groups; +Gitpod.Identity = Identity; +Gitpod.Organizations = Organizations; +Gitpod.Projects = Projects; +Gitpod.Runners = Runners; +Gitpod.Secrets = Secrets; +Gitpod.Usage = Usage; +Gitpod.Users = Users; +export declare namespace Gitpod { + export type RequestOptions = Opts.RequestOptions; + + export import DomainVerificationsPage = Pagination.DomainVerificationsPage; + export { + type DomainVerificationsPageParams as DomainVerificationsPageParams, + type DomainVerificationsPageResponse as DomainVerificationsPageResponse, + }; + + export import EditorsPage = Pagination.EditorsPage; + export { type EditorsPageParams as EditorsPageParams, type EditorsPageResponse as EditorsPageResponse }; + + export import EntriesPage = Pagination.EntriesPage; + export { type EntriesPageParams as EntriesPageParams, type EntriesPageResponse as EntriesPageResponse }; + + export import EnvironmentClassesPage = Pagination.EnvironmentClassesPage; + export { + type EnvironmentClassesPageParams as EnvironmentClassesPageParams, + type EnvironmentClassesPageResponse as EnvironmentClassesPageResponse, + }; + + export import EnvironmentsPage = Pagination.EnvironmentsPage; + export { + type EnvironmentsPageParams as EnvironmentsPageParams, + type EnvironmentsPageResponse as EnvironmentsPageResponse, + }; + + export import GroupsPage = Pagination.GroupsPage; + export { type GroupsPageParams as GroupsPageParams, type GroupsPageResponse as GroupsPageResponse }; + + export import IntegrationsPage = Pagination.IntegrationsPage; + export { + type IntegrationsPageParams as IntegrationsPageParams, + type IntegrationsPageResponse as IntegrationsPageResponse, + }; + + export import LoginProvidersPage = Pagination.LoginProvidersPage; + export { + type LoginProvidersPageParams as LoginProvidersPageParams, + type LoginProvidersPageResponse as LoginProvidersPageResponse, + }; + + export import MembersPage = Pagination.MembersPage; + export { type MembersPageParams as MembersPageParams, type MembersPageResponse as MembersPageResponse }; + + export import PersonalAccessTokensPage = Pagination.PersonalAccessTokensPage; + export { + type PersonalAccessTokensPageParams as PersonalAccessTokensPageParams, + type PersonalAccessTokensPageResponse as PersonalAccessTokensPageResponse, + }; + + export import PoliciesPage = Pagination.PoliciesPage; + export { type PoliciesPageParams as PoliciesPageParams, type PoliciesPageResponse as PoliciesPageResponse }; + + export import ProjectsPage = Pagination.ProjectsPage; + export { type ProjectsPageParams as ProjectsPageParams, type ProjectsPageResponse as ProjectsPageResponse }; + + export import RunnersPage = Pagination.RunnersPage; + export { type RunnersPageParams as RunnersPageParams, type RunnersPageResponse as RunnersPageResponse }; + + export import SecretsPage = Pagination.SecretsPage; + export { type SecretsPageParams as SecretsPageParams, type SecretsPageResponse as SecretsPageResponse }; + + export import ServicesPage = Pagination.ServicesPage; + export { type ServicesPageParams as ServicesPageParams, type ServicesPageResponse as ServicesPageResponse }; + + export import SessionsPage = Pagination.SessionsPage; + export { type SessionsPageParams as SessionsPageParams, type SessionsPageResponse as SessionsPageResponse }; + + export import SSOConfigurationsPage = Pagination.SSOConfigurationsPage; + export { + type SSOConfigurationsPageParams as SSOConfigurationsPageParams, + type SSOConfigurationsPageResponse as SSOConfigurationsPageResponse, + }; + + export import TaskExecutionsPage = Pagination.TaskExecutionsPage; + export { + type TaskExecutionsPageParams as TaskExecutionsPageParams, + type TaskExecutionsPageResponse as TaskExecutionsPageResponse, + }; + + export import TasksPage = Pagination.TasksPage; + export { type TasksPageParams as TasksPageParams, type TasksPageResponse as TasksPageResponse }; + + export import TokensPage = Pagination.TokensPage; + export { type TokensPageParams as TokensPageParams, type TokensPageResponse as TokensPageResponse }; + + export { + Accounts as Accounts, + type Account as Account, + type AccountMembership as AccountMembership, + type JoinableOrganization as JoinableOrganization, + type LoginProvider as LoginProvider, + type AccountRetrieveResponse as AccountRetrieveResponse, + type AccountDeleteResponse as AccountDeleteResponse, + type AccountGetSSOLoginURLResponse as AccountGetSSOLoginURLResponse, + type LoginProvidersLoginProvidersPage as LoginProvidersLoginProvidersPage, + type AccountRetrieveParams as AccountRetrieveParams, + type AccountDeleteParams as AccountDeleteParams, + type AccountGetSSOLoginURLParams as AccountGetSSOLoginURLParams, + type AccountListLoginProvidersParams as AccountListLoginProvidersParams, + }; + + export { + Editors as Editors, + type Editor as Editor, + type EditorRetrieveResponse as EditorRetrieveResponse, + type EditorResolveURLResponse as EditorResolveURLResponse, + type EditorsEditorsPage as EditorsEditorsPage, + type EditorRetrieveParams as EditorRetrieveParams, + type EditorListParams as EditorListParams, + type EditorResolveURLParams as EditorResolveURLParams, + }; + + export { + Environments as Environments, + type AdmissionLevel as AdmissionLevel, + type Environment as Environment, + type EnvironmentActivitySignal as EnvironmentActivitySignal, + type EnvironmentMetadata as EnvironmentMetadata, + type EnvironmentPhase as EnvironmentPhase, + type EnvironmentSpec as EnvironmentSpec, + type EnvironmentStatus as EnvironmentStatus, + type EnvironmentCreateResponse as EnvironmentCreateResponse, + type EnvironmentRetrieveResponse as EnvironmentRetrieveResponse, + type EnvironmentUpdateResponse as EnvironmentUpdateResponse, + type EnvironmentDeleteResponse as EnvironmentDeleteResponse, + type EnvironmentCreateEnvironmentTokenResponse as EnvironmentCreateEnvironmentTokenResponse, + type EnvironmentCreateFromProjectResponse as EnvironmentCreateFromProjectResponse, + type EnvironmentCreateLogsTokenResponse as EnvironmentCreateLogsTokenResponse, + type EnvironmentMarkActiveResponse as EnvironmentMarkActiveResponse, + type EnvironmentStartResponse as EnvironmentStartResponse, + type EnvironmentStopResponse as EnvironmentStopResponse, + type EnvironmentsEnvironmentsPage as EnvironmentsEnvironmentsPage, + type EnvironmentCreateParams as EnvironmentCreateParams, + type EnvironmentRetrieveParams as EnvironmentRetrieveParams, + type EnvironmentUpdateParams as EnvironmentUpdateParams, + type EnvironmentListParams as EnvironmentListParams, + type EnvironmentDeleteParams as EnvironmentDeleteParams, + type EnvironmentCreateEnvironmentTokenParams as EnvironmentCreateEnvironmentTokenParams, + type EnvironmentCreateFromProjectParams as EnvironmentCreateFromProjectParams, + type EnvironmentCreateLogsTokenParams as EnvironmentCreateLogsTokenParams, + type EnvironmentMarkActiveParams as EnvironmentMarkActiveParams, + type EnvironmentStartParams as EnvironmentStartParams, + type EnvironmentStopParams as EnvironmentStopParams, + }; + + export { + Events as Events, + type ResourceOperation as ResourceOperation, + type ResourceType as ResourceType, + type EventListResponse as EventListResponse, + type EventWatchResponse as EventWatchResponse, + type EventListResponsesEntriesPage as EventListResponsesEntriesPage, + type EventListParams as EventListParams, + type EventWatchParams as EventWatchParams, + }; + + export { + Groups as Groups, + type Group as Group, + type GroupsGroupsPage as GroupsGroupsPage, + type GroupListParams as GroupListParams, + }; + + export { + Identity as Identity, + type IDTokenVersion as IDTokenVersion, + type IdentityExchangeTokenResponse as IdentityExchangeTokenResponse, + type IdentityGetAuthenticatedIdentityResponse as IdentityGetAuthenticatedIdentityResponse, + type IdentityGetIDTokenResponse as IdentityGetIDTokenResponse, + type IdentityExchangeTokenParams as IdentityExchangeTokenParams, + type IdentityGetAuthenticatedIdentityParams as IdentityGetAuthenticatedIdentityParams, + type IdentityGetIDTokenParams as IdentityGetIDTokenParams, + }; + + export { + Organizations as Organizations, + type InviteDomains as InviteDomains, + type Organization as Organization, + type OrganizationMember as OrganizationMember, + type OrganizationTier as OrganizationTier, + type OrganizationCreateResponse as OrganizationCreateResponse, + type OrganizationRetrieveResponse as OrganizationRetrieveResponse, + type OrganizationUpdateResponse as OrganizationUpdateResponse, + type OrganizationDeleteResponse as OrganizationDeleteResponse, + type OrganizationJoinResponse as OrganizationJoinResponse, + type OrganizationLeaveResponse as OrganizationLeaveResponse, + type OrganizationSetRoleResponse as OrganizationSetRoleResponse, + type OrganizationMembersMembersPage as OrganizationMembersMembersPage, + type OrganizationCreateParams as OrganizationCreateParams, + type OrganizationRetrieveParams as OrganizationRetrieveParams, + type OrganizationUpdateParams as OrganizationUpdateParams, + type OrganizationDeleteParams as OrganizationDeleteParams, + type OrganizationJoinParams as OrganizationJoinParams, + type OrganizationLeaveParams as OrganizationLeaveParams, + type OrganizationListMembersParams as OrganizationListMembersParams, + type OrganizationSetRoleParams as OrganizationSetRoleParams, + }; + + export { + Projects as Projects, + type EnvironmentInitializer as EnvironmentInitializer, + type Project as Project, + type ProjectEnvironmentClass as ProjectEnvironmentClass, + type ProjectMetadata as ProjectMetadata, + type ProjectCreateResponse as ProjectCreateResponse, + type ProjectRetrieveResponse as ProjectRetrieveResponse, + type ProjectUpdateResponse as ProjectUpdateResponse, + type ProjectDeleteResponse as ProjectDeleteResponse, + type ProjectCreateFromEnvironmentResponse as ProjectCreateFromEnvironmentResponse, + type ProjectsProjectsPage as ProjectsProjectsPage, + type ProjectCreateParams as ProjectCreateParams, + type ProjectRetrieveParams as ProjectRetrieveParams, + type ProjectUpdateParams as ProjectUpdateParams, + type ProjectListParams as ProjectListParams, + type ProjectDeleteParams as ProjectDeleteParams, + type ProjectCreateFromEnvironmentParams as ProjectCreateFromEnvironmentParams, + }; + + export { + Runners as Runners, + type LogLevel as LogLevel, + type MetricsConfiguration as MetricsConfiguration, + type Runner as Runner, + type RunnerCapability as RunnerCapability, + type RunnerConfiguration as RunnerConfiguration, + type RunnerKind as RunnerKind, + type RunnerPhase as RunnerPhase, + type RunnerProvider as RunnerProvider, + type RunnerReleaseChannel as RunnerReleaseChannel, + type RunnerSpec as RunnerSpec, + type RunnerStatus as RunnerStatus, + type RunnerCreateResponse as RunnerCreateResponse, + type RunnerRetrieveResponse as RunnerRetrieveResponse, + type RunnerUpdateResponse as RunnerUpdateResponse, + type RunnerDeleteResponse as RunnerDeleteResponse, + type RunnerCheckAuthenticationForHostResponse as RunnerCheckAuthenticationForHostResponse, + type RunnerCreateRunnerTokenResponse as RunnerCreateRunnerTokenResponse, + type RunnerParseContextURLResponse as RunnerParseContextURLResponse, + type RunnersRunnersPage as RunnersRunnersPage, + type RunnerCreateParams as RunnerCreateParams, + type RunnerRetrieveParams as RunnerRetrieveParams, + type RunnerUpdateParams as RunnerUpdateParams, + type RunnerListParams as RunnerListParams, + type RunnerDeleteParams as RunnerDeleteParams, + type RunnerCheckAuthenticationForHostParams as RunnerCheckAuthenticationForHostParams, + type RunnerCreateRunnerTokenParams as RunnerCreateRunnerTokenParams, + type RunnerParseContextURLParams as RunnerParseContextURLParams, + }; + + export { + Secrets as Secrets, + type Secret as Secret, + type SecretScope as SecretScope, + type SecretCreateResponse as SecretCreateResponse, + type SecretDeleteResponse as SecretDeleteResponse, + type SecretGetValueResponse as SecretGetValueResponse, + type SecretUpdateValueResponse as SecretUpdateValueResponse, + type SecretsSecretsPage as SecretsSecretsPage, + type SecretCreateParams as SecretCreateParams, + type SecretListParams as SecretListParams, + type SecretDeleteParams as SecretDeleteParams, + type SecretGetValueParams as SecretGetValueParams, + type SecretUpdateValueParams as SecretUpdateValueParams, + }; + + export { + Usage as Usage, + type EnvironmentSession as EnvironmentSession, + type EnvironmentSessionsSessionsPage as EnvironmentSessionsSessionsPage, + type UsageListEnvironmentSessionsParams as UsageListEnvironmentSessionsParams, + }; + + export { + Users as Users, + type User as User, + type UserGetAuthenticatedUserResponse as UserGetAuthenticatedUserResponse, + type UserSetSuspendedResponse as UserSetSuspendedResponse, + type UserGetAuthenticatedUserParams as UserGetAuthenticatedUserParams, + type UserSetSuspendedParams as UserSetSuspendedParams, + }; + + export type AutomationTrigger = API.AutomationTrigger; + export type EnvironmentClass = API.EnvironmentClass; + export type ErrorCode = API.ErrorCode; + export type FieldValue = API.FieldValue; + export type OrganizationRole = API.OrganizationRole; + export type Principal = API.Principal; + export type RunsOn = API.RunsOn; + export type Subject = API.Subject; + export type Task = API.Task; + export type TaskExecution = API.TaskExecution; + export type TaskExecutionMetadata = API.TaskExecutionMetadata; + export type TaskExecutionPhase = API.TaskExecutionPhase; + export type TaskExecutionSpec = API.TaskExecutionSpec; + export type TaskExecutionStatus = API.TaskExecutionStatus; + export type TaskMetadata = API.TaskMetadata; + export type TaskSpec = API.TaskSpec; + export type UserStatus = API.UserStatus; +} diff --git a/src/core/README.md b/src/core/README.md new file mode 100644 index 0000000..485fce8 --- /dev/null +++ b/src/core/README.md @@ -0,0 +1,3 @@ +# `core` + +This directory holds public modules implementing non-resource-specific SDK functionality. diff --git a/src/core/api-promise.ts b/src/core/api-promise.ts new file mode 100644 index 0000000..639a545 --- /dev/null +++ b/src/core/api-promise.ts @@ -0,0 +1,92 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { type Gitpod } from '../client'; + +import { type PromiseOrValue } from '../internal/types'; +import { APIResponseProps, defaultParseResponse } from '../internal/parse'; + +/** + * A subclass of `Promise` providing additional helper methods + * for interacting with the SDK. + */ +export class APIPromise<T> extends Promise<T> { + private parsedPromise: Promise<T> | undefined; + #client: Gitpod; + + constructor( + client: Gitpod, + private responsePromise: Promise<APIResponseProps>, + private parseResponse: ( + client: Gitpod, + props: APIResponseProps, + ) => PromiseOrValue<T> = defaultParseResponse, + ) { + super((resolve) => { + // this is maybe a bit weird but this has to be a no-op to not implicitly + // parse the response body; instead .then, .catch, .finally are overridden + // to parse the response + resolve(null as any); + }); + this.#client = client; + } + + _thenUnwrap<U>(transform: (data: T, props: APIResponseProps) => U): APIPromise<U> { + return new APIPromise(this.#client, this.responsePromise, async (client, props) => + transform(await this.parseResponse(client, props), props), + ); + } + + /** + * Gets the raw `Response` instance instead of parsing the response + * data. + * + * If you want to parse the response body but still get the `Response` + * instance, you can use {@link withResponse()}. + * + * 👋 Getting the wrong TypeScript type for `Response`? + * Try setting `"moduleResolution": "NodeNext"` or add `"lib": ["DOM"]` + * to your `tsconfig.json`. + */ + asResponse(): Promise<Response> { + return this.responsePromise.then((p) => p.response); + } + + /** + * Gets the parsed response data and the raw `Response` instance. + * + * If you just want to get the raw `Response` instance without parsing it, + * you can use {@link asResponse()}. + * + * 👋 Getting the wrong TypeScript type for `Response`? + * Try setting `"moduleResolution": "NodeNext"` or add `"lib": ["DOM"]` + * to your `tsconfig.json`. + */ + async withResponse(): Promise<{ data: T; response: Response }> { + const [data, response] = await Promise.all([this.parse(), this.asResponse()]); + return { data, response }; + } + + private parse(): Promise<T> { + if (!this.parsedPromise) { + this.parsedPromise = this.responsePromise.then((data) => this.parseResponse(this.#client, data)); + } + return this.parsedPromise; + } + + override then<TResult1 = T, TResult2 = never>( + onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null, + onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null, + ): Promise<TResult1 | TResult2> { + return this.parse().then(onfulfilled, onrejected); + } + + override catch<TResult = never>( + onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | undefined | null, + ): Promise<T | TResult> { + return this.parse().catch(onrejected); + } + + override finally(onfinally?: (() => void) | undefined | null): Promise<T> { + return this.parse().finally(onfinally); + } +} diff --git a/src/core/error.ts b/src/core/error.ts new file mode 100644 index 0000000..1b22334 --- /dev/null +++ b/src/core/error.ts @@ -0,0 +1,140 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { castToError } from '../internal/errors'; +import * as Shared from '../resources/shared'; + +export class GitpodError extends Error {} + +export class APIError< + TStatus extends number | undefined = number | undefined, + THeaders extends Headers | undefined = Headers | undefined, + TError extends Object | undefined = Object | undefined, +> extends GitpodError { + /** HTTP status for the response that caused the error */ + readonly status: TStatus; + /** HTTP headers for the response that caused the error */ + readonly headers: THeaders; + /** JSON body of the response that caused the error */ + readonly error: TError; + + /** + * The status code, which should be an enum value of + * [google.rpc.Code][google.rpc.Code]. + */ + readonly code?: Shared.ErrorCode | undefined; + + constructor(status: TStatus, error: TError, message: string | undefined, headers: THeaders) { + super(`${APIError.makeMessage(status, error, message)}`); + this.status = status; + this.headers = headers; + this.error = error; + + const data = error as Record<string, any>; + this.code = data?.['code']; + } + + private static makeMessage(status: number | undefined, error: any, message: string | undefined) { + const msg = + error?.message ? + typeof error.message === 'string' ? + error.message + : JSON.stringify(error.message) + : error ? JSON.stringify(error) + : message; + + if (status && msg) { + return `${status} ${msg}`; + } + if (status) { + return `${status} status code (no body)`; + } + if (msg) { + return msg; + } + return '(no status code or body)'; + } + + static generate( + status: number | undefined, + errorResponse: Object | undefined, + message: string | undefined, + headers: Headers | undefined, + ): APIError { + if (!status || !headers) { + return new APIConnectionError({ message, cause: castToError(errorResponse) }); + } + + const error = errorResponse as Record<string, any>; + + if (status === 400) { + return new BadRequestError(status, error, message, headers); + } + + if (status === 401) { + return new AuthenticationError(status, error, message, headers); + } + + if (status === 403) { + return new PermissionDeniedError(status, error, message, headers); + } + + if (status === 404) { + return new NotFoundError(status, error, message, headers); + } + + if (status === 409) { + return new ConflictError(status, error, message, headers); + } + + if (status === 422) { + return new UnprocessableEntityError(status, error, message, headers); + } + + if (status === 429) { + return new RateLimitError(status, error, message, headers); + } + + if (status >= 500) { + return new InternalServerError(status, error, message, headers); + } + + return new APIError(status, error, message, headers); + } +} + +export class APIUserAbortError extends APIError<undefined, undefined, undefined> { + constructor({ message }: { message?: string } = {}) { + super(undefined, undefined, message || 'Request was aborted.', undefined); + } +} + +export class APIConnectionError extends APIError<undefined, undefined, undefined> { + constructor({ message, cause }: { message?: string | undefined; cause?: Error | undefined }) { + super(undefined, undefined, message || 'Connection error.', undefined); + // in some environments the 'cause' property is already declared + // @ts-ignore + if (cause) this.cause = cause; + } +} + +export class APIConnectionTimeoutError extends APIConnectionError { + constructor({ message }: { message?: string } = {}) { + super({ message: message ?? 'Request timed out.' }); + } +} + +export class BadRequestError extends APIError<400, Headers> {} + +export class AuthenticationError extends APIError<401, Headers> {} + +export class PermissionDeniedError extends APIError<403, Headers> {} + +export class NotFoundError extends APIError<404, Headers> {} + +export class ConflictError extends APIError<409, Headers> {} + +export class UnprocessableEntityError extends APIError<422, Headers> {} + +export class RateLimitError extends APIError<429, Headers> {} + +export class InternalServerError extends APIError<number, Headers> {} diff --git a/src/core/pagination.ts b/src/core/pagination.ts new file mode 100644 index 0000000..f72f6ff --- /dev/null +++ b/src/core/pagination.ts @@ -0,0 +1,1220 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { GitpodError } from './error'; +import { FinalRequestOptions } from '../internal/request-options'; +import { defaultParseResponse } from '../internal/parse'; +import { type Gitpod } from '../client'; +import { APIPromise } from './api-promise'; +import { type APIResponseProps } from '../internal/parse'; +import { maybeObj } from '../internal/utils/values'; + +export type PageRequestOptions = Pick<FinalRequestOptions, 'query' | 'headers' | 'body' | 'path' | 'method'>; + +export abstract class AbstractPage<Item> implements AsyncIterable<Item> { + #client: Gitpod; + protected options: FinalRequestOptions; + + protected response: Response; + protected body: unknown; + + constructor(client: Gitpod, response: Response, body: unknown, options: FinalRequestOptions) { + this.#client = client; + this.options = options; + this.response = response; + this.body = body; + } + + abstract nextPageRequestOptions(): PageRequestOptions | null; + + abstract getPaginatedItems(): Item[]; + + hasNextPage(): boolean { + const items = this.getPaginatedItems(); + if (!items.length) return false; + return this.nextPageRequestOptions() != null; + } + + async getNextPage(): Promise<this> { + const nextOptions = this.nextPageRequestOptions(); + if (!nextOptions) { + throw new GitpodError( + 'No next page expected; please check `.hasNextPage()` before calling `.getNextPage()`.', + ); + } + + return await this.#client.requestAPIList(this.constructor as any, nextOptions); + } + + async *iterPages(): AsyncGenerator<this> { + let page: this = this; + yield page; + while (page.hasNextPage()) { + page = await page.getNextPage(); + yield page; + } + } + + async *[Symbol.asyncIterator](): AsyncGenerator<Item> { + for await (const page of this.iterPages()) { + for (const item of page.getPaginatedItems()) { + yield item; + } + } + } +} + +/** + * This subclass of Promise will resolve to an instantiated Page once the request completes. + * + * It also implements AsyncIterable to allow auto-paginating iteration on an unawaited list call, eg: + * + * for await (const item of client.items.list()) { + * console.log(item) + * } + */ +export class PagePromise< + PageClass extends AbstractPage<Item>, + Item = ReturnType<PageClass['getPaginatedItems']>[number], + > + extends APIPromise<PageClass> + implements AsyncIterable<Item> +{ + constructor( + client: Gitpod, + request: Promise<APIResponseProps>, + Page: new (...args: ConstructorParameters<typeof AbstractPage>) => PageClass, + ) { + super( + client, + request, + async (client, props) => + new Page(client, props.response, await defaultParseResponse(client, props), props.options), + ); + } + + /** + * Allow auto-paginating iteration on an unawaited list call, eg: + * + * for await (const item of client.items.list()) { + * console.log(item) + * } + */ + async *[Symbol.asyncIterator]() { + const page = await this; + for await (const item of page) { + yield item; + } + } +} + +export interface DomainVerificationsPageResponse<Item> { + domainVerifications: Array<Item>; + + pagination: DomainVerificationsPageResponse.Pagination; +} + +export namespace DomainVerificationsPageResponse { + export interface Pagination { + nextToken?: string; + } +} + +export interface DomainVerificationsPageParams { + pageSize?: number; + + token?: string; +} + +export class DomainVerificationsPage<Item> + extends AbstractPage<Item> + implements DomainVerificationsPageResponse<Item> +{ + domainVerifications: Array<Item>; + + pagination: DomainVerificationsPageResponse.Pagination; + + constructor( + client: Gitpod, + response: Response, + body: DomainVerificationsPageResponse<Item>, + options: FinalRequestOptions, + ) { + super(client, response, body, options); + + this.domainVerifications = body.domainVerifications || []; + this.pagination = body.pagination || {}; + } + + getPaginatedItems(): Item[] { + return this.domainVerifications ?? []; + } + + nextPageRequestOptions(): PageRequestOptions | null { + const cursor = this.pagination?.nextToken; + if (!cursor) { + return null; + } + + return { + ...this.options, + query: { + ...maybeObj(this.options.query), + token: cursor, + }, + }; + } +} + +export interface EditorsPageResponse<Item> { + editors: Array<Item>; + + pagination: EditorsPageResponse.Pagination; +} + +export namespace EditorsPageResponse { + export interface Pagination { + nextToken?: string; + } +} + +export interface EditorsPageParams { + pageSize?: number; + + token?: string; +} + +export class EditorsPage<Item> extends AbstractPage<Item> implements EditorsPageResponse<Item> { + editors: Array<Item>; + + pagination: EditorsPageResponse.Pagination; + + constructor( + client: Gitpod, + response: Response, + body: EditorsPageResponse<Item>, + options: FinalRequestOptions, + ) { + super(client, response, body, options); + + this.editors = body.editors || []; + this.pagination = body.pagination || {}; + } + + getPaginatedItems(): Item[] { + return this.editors ?? []; + } + + nextPageRequestOptions(): PageRequestOptions | null { + const cursor = this.pagination?.nextToken; + if (!cursor) { + return null; + } + + return { + ...this.options, + query: { + ...maybeObj(this.options.query), + token: cursor, + }, + }; + } +} + +export interface EntriesPageResponse<Item> { + entries: Array<Item>; + + pagination: EntriesPageResponse.Pagination; +} + +export namespace EntriesPageResponse { + export interface Pagination { + nextToken?: string; + } +} + +export interface EntriesPageParams { + pageSize?: number; + + token?: string; +} + +export class EntriesPage<Item> extends AbstractPage<Item> implements EntriesPageResponse<Item> { + entries: Array<Item>; + + pagination: EntriesPageResponse.Pagination; + + constructor( + client: Gitpod, + response: Response, + body: EntriesPageResponse<Item>, + options: FinalRequestOptions, + ) { + super(client, response, body, options); + + this.entries = body.entries || []; + this.pagination = body.pagination || {}; + } + + getPaginatedItems(): Item[] { + return this.entries ?? []; + } + + nextPageRequestOptions(): PageRequestOptions | null { + const cursor = this.pagination?.nextToken; + if (!cursor) { + return null; + } + + return { + ...this.options, + query: { + ...maybeObj(this.options.query), + token: cursor, + }, + }; + } +} + +export interface EnvironmentClassesPageResponse<Item> { + environmentClasses: Array<Item>; + + pagination: EnvironmentClassesPageResponse.Pagination; +} + +export namespace EnvironmentClassesPageResponse { + export interface Pagination { + nextToken?: string; + } +} + +export interface EnvironmentClassesPageParams { + pageSize?: number; + + token?: string; +} + +export class EnvironmentClassesPage<Item> + extends AbstractPage<Item> + implements EnvironmentClassesPageResponse<Item> +{ + environmentClasses: Array<Item>; + + pagination: EnvironmentClassesPageResponse.Pagination; + + constructor( + client: Gitpod, + response: Response, + body: EnvironmentClassesPageResponse<Item>, + options: FinalRequestOptions, + ) { + super(client, response, body, options); + + this.environmentClasses = body.environmentClasses || []; + this.pagination = body.pagination || {}; + } + + getPaginatedItems(): Item[] { + return this.environmentClasses ?? []; + } + + nextPageRequestOptions(): PageRequestOptions | null { + const cursor = this.pagination?.nextToken; + if (!cursor) { + return null; + } + + return { + ...this.options, + query: { + ...maybeObj(this.options.query), + token: cursor, + }, + }; + } +} + +export interface EnvironmentsPageResponse<Item> { + environments: Array<Item>; + + pagination: EnvironmentsPageResponse.Pagination; +} + +export namespace EnvironmentsPageResponse { + export interface Pagination { + nextToken?: string; + } +} + +export interface EnvironmentsPageParams { + pageSize?: number; + + token?: string; +} + +export class EnvironmentsPage<Item> extends AbstractPage<Item> implements EnvironmentsPageResponse<Item> { + environments: Array<Item>; + + pagination: EnvironmentsPageResponse.Pagination; + + constructor( + client: Gitpod, + response: Response, + body: EnvironmentsPageResponse<Item>, + options: FinalRequestOptions, + ) { + super(client, response, body, options); + + this.environments = body.environments || []; + this.pagination = body.pagination || {}; + } + + getPaginatedItems(): Item[] { + return this.environments ?? []; + } + + nextPageRequestOptions(): PageRequestOptions | null { + const cursor = this.pagination?.nextToken; + if (!cursor) { + return null; + } + + return { + ...this.options, + query: { + ...maybeObj(this.options.query), + token: cursor, + }, + }; + } +} + +export interface GroupsPageResponse<Item> { + groups: Array<Item>; + + pagination: GroupsPageResponse.Pagination; +} + +export namespace GroupsPageResponse { + export interface Pagination { + nextToken?: string; + } +} + +export interface GroupsPageParams { + pageSize?: number; + + token?: string; +} + +export class GroupsPage<Item> extends AbstractPage<Item> implements GroupsPageResponse<Item> { + groups: Array<Item>; + + pagination: GroupsPageResponse.Pagination; + + constructor( + client: Gitpod, + response: Response, + body: GroupsPageResponse<Item>, + options: FinalRequestOptions, + ) { + super(client, response, body, options); + + this.groups = body.groups || []; + this.pagination = body.pagination || {}; + } + + getPaginatedItems(): Item[] { + return this.groups ?? []; + } + + nextPageRequestOptions(): PageRequestOptions | null { + const cursor = this.pagination?.nextToken; + if (!cursor) { + return null; + } + + return { + ...this.options, + query: { + ...maybeObj(this.options.query), + token: cursor, + }, + }; + } +} + +export interface IntegrationsPageResponse<Item> { + integrations: Array<Item>; + + pagination: IntegrationsPageResponse.Pagination; +} + +export namespace IntegrationsPageResponse { + export interface Pagination { + nextToken?: string; + } +} + +export interface IntegrationsPageParams { + pageSize?: number; + + token?: string; +} + +export class IntegrationsPage<Item> extends AbstractPage<Item> implements IntegrationsPageResponse<Item> { + integrations: Array<Item>; + + pagination: IntegrationsPageResponse.Pagination; + + constructor( + client: Gitpod, + response: Response, + body: IntegrationsPageResponse<Item>, + options: FinalRequestOptions, + ) { + super(client, response, body, options); + + this.integrations = body.integrations || []; + this.pagination = body.pagination || {}; + } + + getPaginatedItems(): Item[] { + return this.integrations ?? []; + } + + nextPageRequestOptions(): PageRequestOptions | null { + const cursor = this.pagination?.nextToken; + if (!cursor) { + return null; + } + + return { + ...this.options, + query: { + ...maybeObj(this.options.query), + token: cursor, + }, + }; + } +} + +export interface LoginProvidersPageResponse<Item> { + loginProviders: Array<Item>; + + pagination: LoginProvidersPageResponse.Pagination; +} + +export namespace LoginProvidersPageResponse { + export interface Pagination { + nextToken?: string; + } +} + +export interface LoginProvidersPageParams { + pageSize?: number; + + token?: string; +} + +export class LoginProvidersPage<Item> extends AbstractPage<Item> implements LoginProvidersPageResponse<Item> { + loginProviders: Array<Item>; + + pagination: LoginProvidersPageResponse.Pagination; + + constructor( + client: Gitpod, + response: Response, + body: LoginProvidersPageResponse<Item>, + options: FinalRequestOptions, + ) { + super(client, response, body, options); + + this.loginProviders = body.loginProviders || []; + this.pagination = body.pagination || {}; + } + + getPaginatedItems(): Item[] { + return this.loginProviders ?? []; + } + + nextPageRequestOptions(): PageRequestOptions | null { + const cursor = this.pagination?.nextToken; + if (!cursor) { + return null; + } + + return { + ...this.options, + query: { + ...maybeObj(this.options.query), + token: cursor, + }, + }; + } +} + +export interface MembersPageResponse<Item> { + members: Array<Item>; + + pagination: MembersPageResponse.Pagination; +} + +export namespace MembersPageResponse { + export interface Pagination { + nextToken?: string; + } +} + +export interface MembersPageParams { + pageSize?: number; + + token?: string; +} + +export class MembersPage<Item> extends AbstractPage<Item> implements MembersPageResponse<Item> { + members: Array<Item>; + + pagination: MembersPageResponse.Pagination; + + constructor( + client: Gitpod, + response: Response, + body: MembersPageResponse<Item>, + options: FinalRequestOptions, + ) { + super(client, response, body, options); + + this.members = body.members || []; + this.pagination = body.pagination || {}; + } + + getPaginatedItems(): Item[] { + return this.members ?? []; + } + + nextPageRequestOptions(): PageRequestOptions | null { + const cursor = this.pagination?.nextToken; + if (!cursor) { + return null; + } + + return { + ...this.options, + query: { + ...maybeObj(this.options.query), + token: cursor, + }, + }; + } +} + +export interface PersonalAccessTokensPageResponse<Item> { + pagination: PersonalAccessTokensPageResponse.Pagination; + + personalAccessTokens: Array<Item>; +} + +export namespace PersonalAccessTokensPageResponse { + export interface Pagination { + nextToken?: string; + } +} + +export interface PersonalAccessTokensPageParams { + pageSize?: number; + + token?: string; +} + +export class PersonalAccessTokensPage<Item> + extends AbstractPage<Item> + implements PersonalAccessTokensPageResponse<Item> +{ + pagination: PersonalAccessTokensPageResponse.Pagination; + + personalAccessTokens: Array<Item>; + + constructor( + client: Gitpod, + response: Response, + body: PersonalAccessTokensPageResponse<Item>, + options: FinalRequestOptions, + ) { + super(client, response, body, options); + + this.pagination = body.pagination || {}; + this.personalAccessTokens = body.personalAccessTokens || []; + } + + getPaginatedItems(): Item[] { + return this.personalAccessTokens ?? []; + } + + nextPageRequestOptions(): PageRequestOptions | null { + const cursor = this.pagination?.nextToken; + if (!cursor) { + return null; + } + + return { + ...this.options, + query: { + ...maybeObj(this.options.query), + token: cursor, + }, + }; + } +} + +export interface PoliciesPageResponse<Item> { + pagination: PoliciesPageResponse.Pagination; + + policies: Array<Item>; +} + +export namespace PoliciesPageResponse { + export interface Pagination { + nextToken?: string; + } +} + +export interface PoliciesPageParams { + pageSize?: number; + + token?: string; +} + +export class PoliciesPage<Item> extends AbstractPage<Item> implements PoliciesPageResponse<Item> { + pagination: PoliciesPageResponse.Pagination; + + policies: Array<Item>; + + constructor( + client: Gitpod, + response: Response, + body: PoliciesPageResponse<Item>, + options: FinalRequestOptions, + ) { + super(client, response, body, options); + + this.pagination = body.pagination || {}; + this.policies = body.policies || []; + } + + getPaginatedItems(): Item[] { + return this.policies ?? []; + } + + nextPageRequestOptions(): PageRequestOptions | null { + const cursor = this.pagination?.nextToken; + if (!cursor) { + return null; + } + + return { + ...this.options, + query: { + ...maybeObj(this.options.query), + token: cursor, + }, + }; + } +} + +export interface ProjectsPageResponse<Item> { + pagination: ProjectsPageResponse.Pagination; + + projects: Array<Item>; +} + +export namespace ProjectsPageResponse { + export interface Pagination { + nextToken?: string; + } +} + +export interface ProjectsPageParams { + pageSize?: number; + + token?: string; +} + +export class ProjectsPage<Item> extends AbstractPage<Item> implements ProjectsPageResponse<Item> { + pagination: ProjectsPageResponse.Pagination; + + projects: Array<Item>; + + constructor( + client: Gitpod, + response: Response, + body: ProjectsPageResponse<Item>, + options: FinalRequestOptions, + ) { + super(client, response, body, options); + + this.pagination = body.pagination || {}; + this.projects = body.projects || []; + } + + getPaginatedItems(): Item[] { + return this.projects ?? []; + } + + nextPageRequestOptions(): PageRequestOptions | null { + const cursor = this.pagination?.nextToken; + if (!cursor) { + return null; + } + + return { + ...this.options, + query: { + ...maybeObj(this.options.query), + token: cursor, + }, + }; + } +} + +export interface RunnersPageResponse<Item> { + pagination: RunnersPageResponse.Pagination; + + runners: Array<Item>; +} + +export namespace RunnersPageResponse { + export interface Pagination { + nextToken?: string; + } +} + +export interface RunnersPageParams { + pageSize?: number; + + token?: string; +} + +export class RunnersPage<Item> extends AbstractPage<Item> implements RunnersPageResponse<Item> { + pagination: RunnersPageResponse.Pagination; + + runners: Array<Item>; + + constructor( + client: Gitpod, + response: Response, + body: RunnersPageResponse<Item>, + options: FinalRequestOptions, + ) { + super(client, response, body, options); + + this.pagination = body.pagination || {}; + this.runners = body.runners || []; + } + + getPaginatedItems(): Item[] { + return this.runners ?? []; + } + + nextPageRequestOptions(): PageRequestOptions | null { + const cursor = this.pagination?.nextToken; + if (!cursor) { + return null; + } + + return { + ...this.options, + query: { + ...maybeObj(this.options.query), + token: cursor, + }, + }; + } +} + +export interface SecretsPageResponse<Item> { + pagination: SecretsPageResponse.Pagination; + + secrets: Array<Item>; +} + +export namespace SecretsPageResponse { + export interface Pagination { + nextToken?: string; + } +} + +export interface SecretsPageParams { + pageSize?: number; + + token?: string; +} + +export class SecretsPage<Item> extends AbstractPage<Item> implements SecretsPageResponse<Item> { + pagination: SecretsPageResponse.Pagination; + + secrets: Array<Item>; + + constructor( + client: Gitpod, + response: Response, + body: SecretsPageResponse<Item>, + options: FinalRequestOptions, + ) { + super(client, response, body, options); + + this.pagination = body.pagination || {}; + this.secrets = body.secrets || []; + } + + getPaginatedItems(): Item[] { + return this.secrets ?? []; + } + + nextPageRequestOptions(): PageRequestOptions | null { + const cursor = this.pagination?.nextToken; + if (!cursor) { + return null; + } + + return { + ...this.options, + query: { + ...maybeObj(this.options.query), + token: cursor, + }, + }; + } +} + +export interface ServicesPageResponse<Item> { + pagination: ServicesPageResponse.Pagination; + + services: Array<Item>; +} + +export namespace ServicesPageResponse { + export interface Pagination { + nextToken?: string; + } +} + +export interface ServicesPageParams { + pageSize?: number; + + token?: string; +} + +export class ServicesPage<Item> extends AbstractPage<Item> implements ServicesPageResponse<Item> { + pagination: ServicesPageResponse.Pagination; + + services: Array<Item>; + + constructor( + client: Gitpod, + response: Response, + body: ServicesPageResponse<Item>, + options: FinalRequestOptions, + ) { + super(client, response, body, options); + + this.pagination = body.pagination || {}; + this.services = body.services || []; + } + + getPaginatedItems(): Item[] { + return this.services ?? []; + } + + nextPageRequestOptions(): PageRequestOptions | null { + const cursor = this.pagination?.nextToken; + if (!cursor) { + return null; + } + + return { + ...this.options, + query: { + ...maybeObj(this.options.query), + token: cursor, + }, + }; + } +} + +export interface SessionsPageResponse<Item> { + pagination: SessionsPageResponse.Pagination; + + sessions: Array<Item>; +} + +export namespace SessionsPageResponse { + export interface Pagination { + nextToken?: string; + } +} + +export interface SessionsPageParams { + pageSize?: number; + + token?: string; +} + +export class SessionsPage<Item> extends AbstractPage<Item> implements SessionsPageResponse<Item> { + pagination: SessionsPageResponse.Pagination; + + sessions: Array<Item>; + + constructor( + client: Gitpod, + response: Response, + body: SessionsPageResponse<Item>, + options: FinalRequestOptions, + ) { + super(client, response, body, options); + + this.pagination = body.pagination || {}; + this.sessions = body.sessions || []; + } + + getPaginatedItems(): Item[] { + return this.sessions ?? []; + } + + nextPageRequestOptions(): PageRequestOptions | null { + const cursor = this.pagination?.nextToken; + if (!cursor) { + return null; + } + + return { + ...this.options, + query: { + ...maybeObj(this.options.query), + token: cursor, + }, + }; + } +} + +export interface SSOConfigurationsPageResponse<Item> { + pagination: SSOConfigurationsPageResponse.Pagination; + + ssoConfigurations: Array<Item>; +} + +export namespace SSOConfigurationsPageResponse { + export interface Pagination { + nextToken?: string; + } +} + +export interface SSOConfigurationsPageParams { + pageSize?: number; + + token?: string; +} + +export class SSOConfigurationsPage<Item> + extends AbstractPage<Item> + implements SSOConfigurationsPageResponse<Item> +{ + pagination: SSOConfigurationsPageResponse.Pagination; + + ssoConfigurations: Array<Item>; + + constructor( + client: Gitpod, + response: Response, + body: SSOConfigurationsPageResponse<Item>, + options: FinalRequestOptions, + ) { + super(client, response, body, options); + + this.pagination = body.pagination || {}; + this.ssoConfigurations = body.ssoConfigurations || []; + } + + getPaginatedItems(): Item[] { + return this.ssoConfigurations ?? []; + } + + nextPageRequestOptions(): PageRequestOptions | null { + const cursor = this.pagination?.nextToken; + if (!cursor) { + return null; + } + + return { + ...this.options, + query: { + ...maybeObj(this.options.query), + token: cursor, + }, + }; + } +} + +export interface TaskExecutionsPageResponse<Item> { + pagination: TaskExecutionsPageResponse.Pagination; + + taskExecutions: Array<Item>; +} + +export namespace TaskExecutionsPageResponse { + export interface Pagination { + nextToken?: string; + } +} + +export interface TaskExecutionsPageParams { + pageSize?: number; + + token?: string; +} + +export class TaskExecutionsPage<Item> extends AbstractPage<Item> implements TaskExecutionsPageResponse<Item> { + pagination: TaskExecutionsPageResponse.Pagination; + + taskExecutions: Array<Item>; + + constructor( + client: Gitpod, + response: Response, + body: TaskExecutionsPageResponse<Item>, + options: FinalRequestOptions, + ) { + super(client, response, body, options); + + this.pagination = body.pagination || {}; + this.taskExecutions = body.taskExecutions || []; + } + + getPaginatedItems(): Item[] { + return this.taskExecutions ?? []; + } + + nextPageRequestOptions(): PageRequestOptions | null { + const cursor = this.pagination?.nextToken; + if (!cursor) { + return null; + } + + return { + ...this.options, + query: { + ...maybeObj(this.options.query), + token: cursor, + }, + }; + } +} + +export interface TasksPageResponse<Item> { + pagination: TasksPageResponse.Pagination; + + tasks: Array<Item>; +} + +export namespace TasksPageResponse { + export interface Pagination { + nextToken?: string; + } +} + +export interface TasksPageParams { + pageSize?: number; + + token?: string; +} + +export class TasksPage<Item> extends AbstractPage<Item> implements TasksPageResponse<Item> { + pagination: TasksPageResponse.Pagination; + + tasks: Array<Item>; + + constructor( + client: Gitpod, + response: Response, + body: TasksPageResponse<Item>, + options: FinalRequestOptions, + ) { + super(client, response, body, options); + + this.pagination = body.pagination || {}; + this.tasks = body.tasks || []; + } + + getPaginatedItems(): Item[] { + return this.tasks ?? []; + } + + nextPageRequestOptions(): PageRequestOptions | null { + const cursor = this.pagination?.nextToken; + if (!cursor) { + return null; + } + + return { + ...this.options, + query: { + ...maybeObj(this.options.query), + token: cursor, + }, + }; + } +} + +export interface TokensPageResponse<Item> { + pagination: TokensPageResponse.Pagination; + + tokens: Array<Item>; +} + +export namespace TokensPageResponse { + export interface Pagination { + nextToken?: string; + } +} + +export interface TokensPageParams { + pageSize?: number; + + token?: string; +} + +export class TokensPage<Item> extends AbstractPage<Item> implements TokensPageResponse<Item> { + pagination: TokensPageResponse.Pagination; + + tokens: Array<Item>; + + constructor( + client: Gitpod, + response: Response, + body: TokensPageResponse<Item>, + options: FinalRequestOptions, + ) { + super(client, response, body, options); + + this.pagination = body.pagination || {}; + this.tokens = body.tokens || []; + } + + getPaginatedItems(): Item[] { + return this.tokens ?? []; + } + + nextPageRequestOptions(): PageRequestOptions | null { + const cursor = this.pagination?.nextToken; + if (!cursor) { + return null; + } + + return { + ...this.options, + query: { + ...maybeObj(this.options.query), + token: cursor, + }, + }; + } +} diff --git a/src/core/resource.ts b/src/core/resource.ts new file mode 100644 index 0000000..c73b82d --- /dev/null +++ b/src/core/resource.ts @@ -0,0 +1,11 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import type { Gitpod } from '../client'; + +export class APIResource { + protected _client: Gitpod; + + constructor(client: Gitpod) { + this._client = client; + } +} diff --git a/src/core/uploads.ts b/src/core/uploads.ts new file mode 100644 index 0000000..2882ca6 --- /dev/null +++ b/src/core/uploads.ts @@ -0,0 +1,2 @@ +export { type Uploadable } from '../internal/uploads'; +export { toFile, type ToFileInput } from '../internal/to-file'; diff --git a/src/error.ts b/src/error.ts new file mode 100644 index 0000000..fc55f46 --- /dev/null +++ b/src/error.ts @@ -0,0 +1,2 @@ +/** @deprecated Import from ./core/error instead */ +export * from './core/error'; diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 0000000..0eaf4c8 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,23 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export { Gitpod as default } from './client'; + +export { type Uploadable, toFile } from './core/uploads'; +export { APIPromise } from './core/api-promise'; +export { Gitpod, type ClientOptions } from './client'; +export { PagePromise } from './core/pagination'; +export { + GitpodError, + APIError, + APIConnectionError, + APIConnectionTimeoutError, + APIUserAbortError, + NotFoundError, + ConflictError, + RateLimitError, + BadRequestError, + AuthenticationError, + InternalServerError, + PermissionDeniedError, + UnprocessableEntityError, +} from './core/error'; diff --git a/src/internal/README.md b/src/internal/README.md new file mode 100644 index 0000000..3ef5a25 --- /dev/null +++ b/src/internal/README.md @@ -0,0 +1,3 @@ +# `internal` + +The modules in this directory are not importable outside this package and will change between releases. diff --git a/src/internal/builtin-types.ts b/src/internal/builtin-types.ts new file mode 100644 index 0000000..c23d3bd --- /dev/null +++ b/src/internal/builtin-types.ts @@ -0,0 +1,93 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export type Fetch = (input: string | URL | Request, init?: RequestInit) => Promise<Response>; + +/** + * An alias to the builtin `RequestInit` type so we can + * easily alias it in import statements if there are name clashes. + * + * https://developer.mozilla.org/docs/Web/API/RequestInit + */ +type _RequestInit = RequestInit; + +/** + * An alias to the builtin `Response` type so we can + * easily alias it in import statements if there are name clashes. + * + * https://developer.mozilla.org/docs/Web/API/Response + */ +type _Response = Response; + +/** + * The type for the first argument to `fetch`. + * + * https://developer.mozilla.org/docs/Web/API/Window/fetch#resource + */ +type _RequestInfo = Request | URL | string; + +/** + * The type for constructing `RequestInit` Headers. + * + * https://developer.mozilla.org/docs/Web/API/RequestInit#setting_headers + */ +type _HeadersInit = RequestInit['headers']; + +/** + * The type for constructing `RequestInit` body. + * + * https://developer.mozilla.org/docs/Web/API/RequestInit#body + */ +type _BodyInit = RequestInit['body']; + +/** + * An alias to the builtin `Array<T>` type so we can + * easily alias it in import statements if there are name clashes. + */ +type _Array<T> = Array<T>; + +/** + * An alias to the builtin `Record<K, T>` type so we can + * easily alias it in import statements if there are name clashes. + */ +type _Record<K extends keyof any, T> = Record<K, T>; + +export type { + _Array as Array, + _BodyInit as BodyInit, + _HeadersInit as HeadersInit, + _Record as Record, + _RequestInfo as RequestInfo, + _RequestInit as RequestInit, + _Response as Response, +}; + +/** + * A copy of the builtin `EndingType` type as it isn't fully supported in certain + * environments and attempting to reference the global version will error. + * + * https://github.com/microsoft/TypeScript/blob/49ad1a3917a0ea57f5ff248159256e12bb1cb705/src/lib/dom.generated.d.ts#L27941 + */ +type EndingType = 'native' | 'transparent'; + +/** + * A copy of the builtin `BlobPropertyBag` type as it isn't fully supported in certain + * environments and attempting to reference the global version will error. + * + * https://github.com/microsoft/TypeScript/blob/49ad1a3917a0ea57f5ff248159256e12bb1cb705/src/lib/dom.generated.d.ts#L154 + * https://developer.mozilla.org/en-US/docs/Web/API/Blob/Blob#options + */ +export interface BlobPropertyBag { + endings?: EndingType; + type?: string; +} + +/** + * A copy of the builtin `FilePropertyBag` type as it isn't fully supported in certain + * environments and attempting to reference the global version will error. + * + * https://github.com/microsoft/TypeScript/blob/49ad1a3917a0ea57f5ff248159256e12bb1cb705/src/lib/dom.generated.d.ts#L503 + * https://developer.mozilla.org/en-US/docs/Web/API/File/File#options + */ +export interface FilePropertyBag extends BlobPropertyBag { + lastModified?: number; +} diff --git a/src/internal/decoders/jsonl.ts b/src/internal/decoders/jsonl.ts new file mode 100644 index 0000000..79ec5f8 --- /dev/null +++ b/src/internal/decoders/jsonl.ts @@ -0,0 +1,48 @@ +import { GitpodError } from '../../core/error'; +import { ReadableStreamToAsyncIterable } from '../shims'; +import { LineDecoder, type Bytes } from './line'; + +export class JSONLDecoder<T> { + controller: AbortController; + + constructor( + private iterator: AsyncIterableIterator<Bytes>, + controller: AbortController, + ) { + this.controller = controller; + } + + private async *decoder(): AsyncIterator<T, any, undefined> { + const lineDecoder = new LineDecoder(); + for await (const chunk of this.iterator) { + for (const line of lineDecoder.decode(chunk)) { + yield JSON.parse(line); + } + } + + for (const line of lineDecoder.flush()) { + yield JSON.parse(line); + } + } + + [Symbol.asyncIterator](): AsyncIterator<T> { + return this.decoder(); + } + + static fromResponse<T>(response: Response, controller: AbortController): JSONLDecoder<T> { + if (!response.body) { + controller.abort(); + if ( + typeof (globalThis as any).navigator !== 'undefined' && + (globalThis as any).navigator.product === 'ReactNative' + ) { + throw new GitpodError( + `The default react-native fetch implementation does not support streaming. Please use expo/fetch: https://docs.expo.dev/versions/latest/sdk/expo/#expofetch-api`, + ); + } + throw new GitpodError(`Attempted to iterate over a response with no body`); + } + + return new JSONLDecoder(ReadableStreamToAsyncIterable<Bytes>(response.body), controller); + } +} diff --git a/src/internal/decoders/line.ts b/src/internal/decoders/line.ts new file mode 100644 index 0000000..b3bfa97 --- /dev/null +++ b/src/internal/decoders/line.ts @@ -0,0 +1,135 @@ +import { concatBytes, decodeUTF8, encodeUTF8 } from '../utils/bytes'; + +export type Bytes = string | ArrayBuffer | Uint8Array | null | undefined; + +/** + * A re-implementation of httpx's `LineDecoder` in Python that handles incrementally + * reading lines from text. + * + * https://github.com/encode/httpx/blob/920333ea98118e9cf617f246905d7b202510941c/httpx/_decoders.py#L258 + */ +export class LineDecoder { + // prettier-ignore + static NEWLINE_CHARS = new Set(['\n', '\r']); + static NEWLINE_REGEXP = /\r\n|[\n\r]/g; + + #buffer: Uint8Array; + #carriageReturnIndex: number | null; + + constructor() { + this.#buffer = new Uint8Array(); + this.#carriageReturnIndex = null; + } + + decode(chunk: Bytes): string[] { + if (chunk == null) { + return []; + } + + const binaryChunk = + chunk instanceof ArrayBuffer ? new Uint8Array(chunk) + : typeof chunk === 'string' ? encodeUTF8(chunk) + : chunk; + + this.#buffer = concatBytes([this.#buffer, binaryChunk]); + + const lines: string[] = []; + let patternIndex; + while ((patternIndex = findNewlineIndex(this.#buffer, this.#carriageReturnIndex)) != null) { + if (patternIndex.carriage && this.#carriageReturnIndex == null) { + // skip until we either get a corresponding `\n`, a new `\r` or nothing + this.#carriageReturnIndex = patternIndex.index; + continue; + } + + // we got double \r or \rtext\n + if ( + this.#carriageReturnIndex != null && + (patternIndex.index !== this.#carriageReturnIndex + 1 || patternIndex.carriage) + ) { + lines.push(decodeUTF8(this.#buffer.subarray(0, this.#carriageReturnIndex - 1))); + this.#buffer = this.#buffer.subarray(this.#carriageReturnIndex); + this.#carriageReturnIndex = null; + continue; + } + + const endIndex = + this.#carriageReturnIndex !== null ? patternIndex.preceding - 1 : patternIndex.preceding; + + const line = decodeUTF8(this.#buffer.subarray(0, endIndex)); + lines.push(line); + + this.#buffer = this.#buffer.subarray(patternIndex.index); + this.#carriageReturnIndex = null; + } + + return lines; + } + + flush(): string[] { + if (!this.#buffer.length) { + return []; + } + return this.decode('\n'); + } +} + +/** + * This function searches the buffer for the end patterns, (\r or \n) + * and returns an object with the index preceding the matched newline and the + * index after the newline char. `null` is returned if no new line is found. + * + * ```ts + * findNewLineIndex('abc\ndef') -> { preceding: 2, index: 3 } + * ``` + */ +function findNewlineIndex( + buffer: Uint8Array, + startIndex: number | null, +): { preceding: number; index: number; carriage: boolean } | null { + const newline = 0x0a; // \n + const carriage = 0x0d; // \r + + for (let i = startIndex ?? 0; i < buffer.length; i++) { + if (buffer[i] === newline) { + return { preceding: i, index: i + 1, carriage: false }; + } + + if (buffer[i] === carriage) { + return { preceding: i, index: i + 1, carriage: true }; + } + } + + return null; +} + +export function findDoubleNewlineIndex(buffer: Uint8Array): number { + // This function searches the buffer for the end patterns (\r\r, \n\n, \r\n\r\n) + // and returns the index right after the first occurrence of any pattern, + // or -1 if none of the patterns are found. + const newline = 0x0a; // \n + const carriage = 0x0d; // \r + + for (let i = 0; i < buffer.length - 1; i++) { + if (buffer[i] === newline && buffer[i + 1] === newline) { + // \n\n + return i + 2; + } + if (buffer[i] === carriage && buffer[i + 1] === carriage) { + // \r\r + return i + 2; + } + if ( + buffer[i] === carriage && + buffer[i + 1] === newline && + i + 3 < buffer.length && + buffer[i + 2] === carriage && + buffer[i + 3] === newline + ) { + // \r\n\r\n + return i + 4; + } + } + + return -1; +} diff --git a/src/internal/detect-platform.ts b/src/internal/detect-platform.ts new file mode 100644 index 0000000..c5e273b --- /dev/null +++ b/src/internal/detect-platform.ts @@ -0,0 +1,196 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { VERSION } from '../version'; + +export const isRunningInBrowser = () => { + return ( + // @ts-ignore + typeof window !== 'undefined' && + // @ts-ignore + typeof window.document !== 'undefined' && + // @ts-ignore + typeof navigator !== 'undefined' + ); +}; + +type DetectedPlatform = 'deno' | 'node' | 'edge' | 'unknown'; + +/** + * Note this does not detect 'browser'; for that, use getBrowserInfo(). + */ +function getDetectedPlatform(): DetectedPlatform { + if (typeof Deno !== 'undefined' && Deno.build != null) { + return 'deno'; + } + if (typeof EdgeRuntime !== 'undefined') { + return 'edge'; + } + if ( + Object.prototype.toString.call( + typeof (globalThis as any).process !== 'undefined' ? (globalThis as any).process : 0, + ) === '[object process]' + ) { + return 'node'; + } + return 'unknown'; +} + +declare const Deno: any; +declare const EdgeRuntime: any; +type Arch = 'x32' | 'x64' | 'arm' | 'arm64' | `other:${string}` | 'unknown'; +type PlatformName = + | 'MacOS' + | 'Linux' + | 'Windows' + | 'FreeBSD' + | 'OpenBSD' + | 'iOS' + | 'Android' + | `Other:${string}` + | 'Unknown'; +type Browser = 'ie' | 'edge' | 'chrome' | 'firefox' | 'safari'; +type PlatformProperties = { + 'X-Stainless-Lang': 'js'; + 'X-Stainless-Package-Version': string; + 'X-Stainless-OS': PlatformName; + 'X-Stainless-Arch': Arch; + 'X-Stainless-Runtime': 'node' | 'deno' | 'edge' | `browser:${Browser}` | 'unknown'; + 'X-Stainless-Runtime-Version': string; +}; +const getPlatformProperties = (): PlatformProperties => { + const detectedPlatform = getDetectedPlatform(); + if (detectedPlatform === 'deno') { + return { + 'X-Stainless-Lang': 'js', + 'X-Stainless-Package-Version': VERSION, + 'X-Stainless-OS': normalizePlatform(Deno.build.os), + 'X-Stainless-Arch': normalizeArch(Deno.build.arch), + 'X-Stainless-Runtime': 'deno', + 'X-Stainless-Runtime-Version': + typeof Deno.version === 'string' ? Deno.version : Deno.version?.deno ?? 'unknown', + }; + } + if (typeof EdgeRuntime !== 'undefined') { + return { + 'X-Stainless-Lang': 'js', + 'X-Stainless-Package-Version': VERSION, + 'X-Stainless-OS': 'Unknown', + 'X-Stainless-Arch': `other:${EdgeRuntime}`, + 'X-Stainless-Runtime': 'edge', + 'X-Stainless-Runtime-Version': (globalThis as any).process.version, + }; + } + // Check if Node.js + if (detectedPlatform === 'node') { + return { + 'X-Stainless-Lang': 'js', + 'X-Stainless-Package-Version': VERSION, + 'X-Stainless-OS': normalizePlatform((globalThis as any).process.platform), + 'X-Stainless-Arch': normalizeArch((globalThis as any).process.arch), + 'X-Stainless-Runtime': 'node', + 'X-Stainless-Runtime-Version': (globalThis as any).process.version, + }; + } + + const browserInfo = getBrowserInfo(); + if (browserInfo) { + return { + 'X-Stainless-Lang': 'js', + 'X-Stainless-Package-Version': VERSION, + 'X-Stainless-OS': 'Unknown', + 'X-Stainless-Arch': 'unknown', + 'X-Stainless-Runtime': `browser:${browserInfo.browser}`, + 'X-Stainless-Runtime-Version': browserInfo.version, + }; + } + + // TODO add support for Cloudflare workers, etc. + return { + 'X-Stainless-Lang': 'js', + 'X-Stainless-Package-Version': VERSION, + 'X-Stainless-OS': 'Unknown', + 'X-Stainless-Arch': 'unknown', + 'X-Stainless-Runtime': 'unknown', + 'X-Stainless-Runtime-Version': 'unknown', + }; +}; + +type BrowserInfo = { + browser: Browser; + version: string; +}; + +declare const navigator: { userAgent: string } | undefined; + +// Note: modified from https://github.com/JS-DevTools/host-environment/blob/b1ab79ecde37db5d6e163c050e54fe7d287d7c92/src/isomorphic.browser.ts +function getBrowserInfo(): BrowserInfo | null { + if (typeof navigator === 'undefined' || !navigator) { + return null; + } + + // NOTE: The order matters here! + const browserPatterns = [ + { key: 'edge' as const, pattern: /Edge(?:\W+(\d+)\.(\d+)(?:\.(\d+))?)?/ }, + { key: 'ie' as const, pattern: /MSIE(?:\W+(\d+)\.(\d+)(?:\.(\d+))?)?/ }, + { key: 'ie' as const, pattern: /Trident(?:.*rv\:(\d+)\.(\d+)(?:\.(\d+))?)?/ }, + { key: 'chrome' as const, pattern: /Chrome(?:\W+(\d+)\.(\d+)(?:\.(\d+))?)?/ }, + { key: 'firefox' as const, pattern: /Firefox(?:\W+(\d+)\.(\d+)(?:\.(\d+))?)?/ }, + { key: 'safari' as const, pattern: /(?:Version\W+(\d+)\.(\d+)(?:\.(\d+))?)?(?:\W+Mobile\S*)?\W+Safari/ }, + ]; + + // Find the FIRST matching browser + for (const { key, pattern } of browserPatterns) { + const match = pattern.exec(navigator.userAgent); + if (match) { + const major = match[1] || 0; + const minor = match[2] || 0; + const patch = match[3] || 0; + + return { browser: key, version: `${major}.${minor}.${patch}` }; + } + } + + return null; +} + +const normalizeArch = (arch: string): Arch => { + // Node docs: + // - https://nodejs.org/api/process.html#processarch + // Deno docs: + // - https://doc.deno.land/deno/stable/~/Deno.build + if (arch === 'x32') return 'x32'; + if (arch === 'x86_64' || arch === 'x64') return 'x64'; + if (arch === 'arm') return 'arm'; + if (arch === 'aarch64' || arch === 'arm64') return 'arm64'; + if (arch) return `other:${arch}`; + return 'unknown'; +}; + +const normalizePlatform = (platform: string): PlatformName => { + // Node platforms: + // - https://nodejs.org/api/process.html#processplatform + // Deno platforms: + // - https://doc.deno.land/deno/stable/~/Deno.build + // - https://github.com/denoland/deno/issues/14799 + + platform = platform.toLowerCase(); + + // NOTE: this iOS check is untested and may not work + // Node does not work natively on IOS, there is a fork at + // https://github.com/nodejs-mobile/nodejs-mobile + // however it is unknown at the time of writing how to detect if it is running + if (platform.includes('ios')) return 'iOS'; + if (platform === 'android') return 'Android'; + if (platform === 'darwin') return 'MacOS'; + if (platform === 'win32') return 'Windows'; + if (platform === 'freebsd') return 'FreeBSD'; + if (platform === 'openbsd') return 'OpenBSD'; + if (platform === 'linux') return 'Linux'; + if (platform) return `Other:${platform}`; + return 'Unknown'; +}; + +let _platformHeaders: PlatformProperties; +export const getPlatformHeaders = () => { + return (_platformHeaders ??= getPlatformProperties()); +}; diff --git a/src/internal/errors.ts b/src/internal/errors.ts new file mode 100644 index 0000000..82c7b14 --- /dev/null +++ b/src/internal/errors.ts @@ -0,0 +1,33 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export function isAbortError(err: unknown) { + return ( + typeof err === 'object' && + err !== null && + // Spec-compliant fetch implementations + (('name' in err && (err as any).name === 'AbortError') || + // Expo fetch + ('message' in err && String((err as any).message).includes('FetchRequestCanceledException'))) + ); +} + +export const castToError = (err: any): Error => { + if (err instanceof Error) return err; + if (typeof err === 'object' && err !== null) { + try { + if (Object.prototype.toString.call(err) === '[object Error]') { + // @ts-ignore - not all envs have native support for cause yet + const error = new Error(err.message, err.cause ? { cause: err.cause } : {}); + if (err.stack) error.stack = err.stack; + // @ts-ignore - not all envs have native support for cause yet + if (err.cause && !error.cause) error.cause = err.cause; + if (err.name) error.name = err.name; + return error; + } + } catch {} + try { + return new Error(JSON.stringify(err)); + } catch {} + } + return new Error(err); +}; diff --git a/src/internal/headers.ts b/src/internal/headers.ts new file mode 100644 index 0000000..8659dde --- /dev/null +++ b/src/internal/headers.ts @@ -0,0 +1,97 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +type HeaderValue = string | undefined | null; +export type HeadersLike = + | Headers + | readonly HeaderValue[][] + | Record<string, HeaderValue | readonly HeaderValue[]> + | undefined + | null + | NullableHeaders; + +const brand_privateNullableHeaders = Symbol('brand.privateNullableHeaders'); + +/** + * @internal + * Users can pass explicit nulls to unset default headers. When we parse them + * into a standard headers type we need to preserve that information. + */ +export type NullableHeaders = { + /** Brand check, prevent users from creating a NullableHeaders. */ + [brand_privateNullableHeaders]: true; + /** Parsed headers. */ + values: Headers; + /** Set of lowercase header names explicitly set to null. */ + nulls: Set<string>; +}; + +const isArray = Array.isArray as (val: unknown) => val is readonly unknown[]; + +function* iterateHeaders(headers: HeadersLike): IterableIterator<readonly [string, string | null]> { + if (!headers) return; + + if (brand_privateNullableHeaders in headers) { + const { values, nulls } = headers; + yield* values.entries(); + for (const name of nulls) { + yield [name, null]; + } + return; + } + + let shouldClear = false; + let iter: Iterable<readonly (HeaderValue | readonly HeaderValue[])[]>; + if (headers instanceof Headers) { + iter = headers.entries(); + } else if (isArray(headers)) { + iter = headers; + } else { + shouldClear = true; + iter = Object.entries(headers ?? {}); + } + for (let row of iter) { + const name = row[0]; + if (typeof name !== 'string') throw new TypeError('expected header name to be a string'); + const values = isArray(row[1]) ? row[1] : [row[1]]; + let didClear = false; + for (const value of values) { + if (value === undefined) continue; + + // Objects keys always overwrite older headers, they never append. + // Yield a null to clear the header before adding the new values. + if (shouldClear && !didClear) { + didClear = true; + yield [name, null]; + } + yield [name, value]; + } + } +} + +export const buildHeaders = (newHeaders: HeadersLike[]): NullableHeaders => { + const targetHeaders = new Headers(); + const nullHeaders = new Set<string>(); + const seenHeaders = new Set<string>(); + for (const headers of newHeaders) { + for (const [name, value] of iterateHeaders(headers)) { + const lowerName = name.toLowerCase(); + if (!seenHeaders.has(lowerName)) { + targetHeaders.delete(name); + seenHeaders.add(lowerName); + } + if (value === null) { + targetHeaders.delete(name); + nullHeaders.add(lowerName); + } else { + targetHeaders.append(name, value); + nullHeaders.delete(lowerName); + } + } + } + return { [brand_privateNullableHeaders]: true, values: targetHeaders, nulls: nullHeaders }; +}; + +export const isEmptyHeaders = (headers: HeadersLike) => { + for (const _ of iterateHeaders(headers)) return false; + return true; +}; diff --git a/src/internal/parse.ts b/src/internal/parse.ts new file mode 100644 index 0000000..a12647d --- /dev/null +++ b/src/internal/parse.ts @@ -0,0 +1,50 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import type { FinalRequestOptions } from './request-options'; +import { type Gitpod } from '../client'; +import { formatRequestDetails, loggerFor } from './utils/log'; + +export type APIResponseProps = { + response: Response; + options: FinalRequestOptions; + controller: AbortController; + requestLogID: string; + retryOfRequestLogID: string | undefined; + startTime: number; +}; + +export async function defaultParseResponse<T>(client: Gitpod, props: APIResponseProps): Promise<T> { + const { response, requestLogID, retryOfRequestLogID, startTime } = props; + const body = await (async () => { + // fetch refuses to read the body when the status code is 204. + if (response.status === 204) { + return null as T; + } + + if (props.options.__binaryResponse) { + return response as unknown as T; + } + + const contentType = response.headers.get('content-type'); + const mediaType = contentType?.split(';')[0]?.trim(); + const isJSON = mediaType?.includes('application/json') || mediaType?.endsWith('+json'); + if (isJSON) { + const json = await response.json(); + return json as T; + } + + const text = await response.text(); + return text as unknown as T; + })(); + loggerFor(client).debug( + `[${requestLogID}] response parsed`, + formatRequestDetails({ + retryOfRequestLogID, + url: response.url, + status: response.status, + body, + durationMs: Date.now() - startTime, + }), + ); + return body; +} diff --git a/src/internal/request-options.ts b/src/internal/request-options.ts new file mode 100644 index 0000000..d2ade9e --- /dev/null +++ b/src/internal/request-options.ts @@ -0,0 +1,37 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { NullableHeaders } from './headers'; + +import type { BodyInit } from './builtin-types'; +import type { HTTPMethod, MergedRequestInit } from './types'; +import { type HeadersLike } from './headers'; + +export type FinalRequestOptions = RequestOptions & { method: HTTPMethod; path: string }; + +export type RequestOptions = { + method?: HTTPMethod; + path?: string; + query?: object | undefined | null; + body?: unknown; + headers?: HeadersLike; + maxRetries?: number; + stream?: boolean | undefined; + timeout?: number; + fetchOptions?: MergedRequestInit; + signal?: AbortSignal | undefined | null; + idempotencyKey?: string; + + __binaryResponse?: boolean | undefined; +}; + +export type EncodedContent = { bodyHeaders: HeadersLike; body: BodyInit }; +export type RequestEncoder = (request: { headers: NullableHeaders; body: unknown }) => EncodedContent; + +export const FallbackEncoder: RequestEncoder = ({ headers, body }) => { + return { + bodyHeaders: { + 'content-type': 'application/json', + }, + body: JSON.stringify(body), + }; +}; diff --git a/src/internal/shim-types.d.ts b/src/internal/shim-types.d.ts new file mode 100644 index 0000000..fe48144 --- /dev/null +++ b/src/internal/shim-types.d.ts @@ -0,0 +1,28 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +/** + * Shims for types that we can't always rely on being available globally. + * + * Note: these only exist at the type-level, there is no corresponding runtime + * version for any of these symbols. + */ + +/** + * In order to properly access the global `NodeJS` type, if it's available, we + * need to make use of declaration shadowing. Without this, any checks for the + * presence of `NodeJS.ReadableStream` will fail. + */ +declare namespace NodeJS { + interface ReadableStream {} +} + +type HasProperties<T> = keyof T extends never ? false : true; + +// @ts-ignore +type _ReadableStream<R = any> = + // @ts-ignore + HasProperties<NodeJS.ReadableStream> extends true ? NodeJS.ReadableStream<R> : ReadableStream<R>; + +// @ts-ignore +declare const _ReadableStream: unknown extends typeof ReadableStream ? never : typeof ReadableStream; +export { _ReadableStream as ReadableStream }; diff --git a/src/internal/shims.ts b/src/internal/shims.ts new file mode 100644 index 0000000..95b03fb --- /dev/null +++ b/src/internal/shims.ts @@ -0,0 +1,107 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +/** + * This module provides internal shims and utility functions for environments where certain Node.js or global types may not be available. + * + * These are used to ensure we can provide a consistent behaviour between different JavaScript environments and good error + * messages in cases where an environment isn't fully supported. + */ + +import { type Fetch } from './builtin-types'; +import { type ReadableStream } from './shim-types'; + +export function getDefaultFetch(): Fetch { + if (typeof fetch !== 'undefined') { + return fetch as any; + } + + throw new Error( + '`fetch` is not defined as a global; Either pass `fetch` to the client, `new Gitpod({ fetch })` or polyfill the global, `globalThis.fetch = fetch`', + ); +} + +type ReadableStreamArgs = ConstructorParameters<typeof ReadableStream>; + +export function makeReadableStream(...args: ReadableStreamArgs): ReadableStream { + const ReadableStream = (globalThis as any).ReadableStream; + if (typeof ReadableStream === 'undefined') { + // Note: All of the platforms / runtimes we officially support already define + // `ReadableStream` as a global, so this should only ever be hit on unsupported runtimes. + throw new Error( + '`ReadableStream` is not defined as a global; You will need to polyfill it, `globalThis.ReadableStream = ReadableStream`', + ); + } + + return new ReadableStream(...args); +} + +export function ReadableStreamFrom<T>(iterable: Iterable<T> | AsyncIterable<T>): ReadableStream<T> { + let iter: AsyncIterator<T> | Iterator<T> = + Symbol.asyncIterator in iterable ? iterable[Symbol.asyncIterator]() : iterable[Symbol.iterator](); + + return makeReadableStream({ + start() {}, + async pull(controller: any) { + const { done, value } = await iter.next(); + if (done) { + controller.close(); + } else { + controller.enqueue(value); + } + }, + async cancel() { + await iter.return?.(); + }, + }); +} + +/** + * Most browsers don't yet have async iterable support for ReadableStream, + * and Node has a very different way of reading bytes from its "ReadableStream". + * + * This polyfill was pulled from https://github.com/MattiasBuelens/web-streams-polyfill/pull/122#issuecomment-1627354490 + */ +export function ReadableStreamToAsyncIterable<T>(stream: any): AsyncIterableIterator<T> { + if (stream[Symbol.asyncIterator]) return stream; + + const reader = stream.getReader(); + return { + async next() { + try { + const result = await reader.read(); + if (result?.done) reader.releaseLock(); // release lock when stream becomes closed + return result; + } catch (e) { + reader.releaseLock(); // release lock when stream becomes errored + throw e; + } + }, + async return() { + const cancelPromise = reader.cancel(); + reader.releaseLock(); + await cancelPromise; + return { done: true, value: undefined }; + }, + [Symbol.asyncIterator]() { + return this; + }, + }; +} + +/** + * Cancels a ReadableStream we don't need to consume. + * See https://undici.nodejs.org/#/?id=garbage-collection + */ +export async function CancelReadableStream(stream: any): Promise<void> { + if (stream === null || typeof stream !== 'object') return; + + if (stream[Symbol.asyncIterator]) { + await stream[Symbol.asyncIterator]().return?.(); + return; + } + + const reader = stream.getReader(); + const cancelPromise = reader.cancel(); + reader.releaseLock(); + await cancelPromise; +} diff --git a/src/internal/shims/crypto.ts b/src/internal/shims/crypto.ts new file mode 100644 index 0000000..905f81c --- /dev/null +++ b/src/internal/shims/crypto.ts @@ -0,0 +1,18 @@ +import { getBuiltinModule } from './getBuiltinModule'; + +type Crypto = { + /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Crypto/getRandomValues) */ + getRandomValues<T extends ArrayBufferView | null>(array: T): T; + /** + * Available only in secure contexts. + * + * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Crypto/randomUUID) + */ + randomUUID?: () => string; +}; +export let getCrypto: () => Crypto | undefined = function lazyGetCrypto() { + if (getCrypto !== lazyGetCrypto) return getCrypto(); + const crypto: Crypto = (globalThis as any).crypto || (getBuiltinModule?.('node:crypto') as any)?.webcrypto; + getCrypto = () => crypto; + return crypto; +}; diff --git a/src/internal/shims/file.ts b/src/internal/shims/file.ts new file mode 100644 index 0000000..d5dc820 --- /dev/null +++ b/src/internal/shims/file.ts @@ -0,0 +1,32 @@ +import { getBuiltinModule } from './getBuiltinModule'; + +export let getFile = function lazyGetFile(): FileConstructor { + if (getFile !== lazyGetFile) return getFile(); + // We can drop getBuiltinModule once we no longer support Node < 20.0.0 + const File = (globalThis as any).File ?? (getBuiltinModule?.('node:buffer') as any)?.File; + if (!File) throw new Error('`File` is not defined as a global, which is required for file uploads.'); + getFile = () => File; + return File; +}; + +type FileConstructor = + typeof globalThis extends { File: infer fileConstructor } ? fileConstructor : typeof FallbackFile; +export type File = InstanceType<FileConstructor>; + +// The infer is to make TS show it as a nice union type, +// instead of literally `ConstructorParameters<typeof Blob>[0]` +type FallbackBlobSource = ConstructorParameters<typeof Blob>[0] extends infer T ? T : never; +/** + * A [`File`](https://developer.mozilla.org/en-US/docs/Web/API/File) provides information about files. + */ +declare class FallbackFile extends Blob { + constructor(sources: FallbackBlobSource, fileName: string, options?: any); + /** + * The name of the `File`. + */ + readonly name: string; + /** + * The last modified date of the `File`. + */ + readonly lastModified: number; +} diff --git a/src/internal/shims/getBuiltinModule.ts b/src/internal/shims/getBuiltinModule.ts new file mode 100644 index 0000000..64daa2c --- /dev/null +++ b/src/internal/shims/getBuiltinModule.ts @@ -0,0 +1,66 @@ +/** + * Load a Node built-in module. ID may or may not be prefixed by `node:` and + * will be normalized. If we used static imports then our bundle size would be bloated by + * injected polyfills, and if we used dynamic require then in addition to bundlers logging warnings, + * our code would not work when bundled to ESM and run in Node 18. + * @param {string} id ID of the built-in to be loaded. + * @returns {object|undefined} exports of the built-in. Undefined if the built-in + * does not exist. + */ +export let getBuiltinModule: null | ((id: string) => object | undefined) = function getBuiltinModuleLazy( + id: string, +): object | undefined { + try { + if (getBuiltinModule !== getBuiltinModuleLazy) return getBuiltinModule!(id); + if ((process as any).getBuiltinModule) { + getBuiltinModule = (process as any).getBuiltinModule; + } else { + /* Fallback implementation for Node 18 */ + function createFallbackGetBuiltinModule(BuiltinModule: any) { + return function getBuiltinModule(id: string): object | undefined { + id = BuiltinModule.normalizeRequirableId(String(id)); + if (!BuiltinModule.canBeRequiredByUsers(id)) { + return; + } + const mod = BuiltinModule.map.get(id); + mod.compileForPublicLoader(); + return mod.exports; + }; + } + const magicKey = Math.random() + ''; + let module: { BuiltinModule: any } | undefined; + let ObjectPrototype: {} = Blob; + for (let next; (next = Reflect.getPrototypeOf(ObjectPrototype)); ObjectPrototype = next); + try { + const kClone = Object.getOwnPropertySymbols(Blob.prototype).find( + (e) => e.description?.includes('clone'), + )!; + Object.defineProperty(ObjectPrototype, magicKey, { + get() { + module = this; + throw null; + }, + configurable: true, + }); + structuredClone( + new (class extends Blob { + [kClone]() { + return { + deserializeInfo: 'internal/bootstrap/realm:' + magicKey, + }; + } + })([]), + ); + } catch {} + delete (ObjectPrototype as any)[magicKey]; + if (module) { + getBuiltinModule = createFallbackGetBuiltinModule(module.BuiltinModule); + } else { + getBuiltinModule = () => undefined; + } + } + return getBuiltinModule!(id); + } catch { + return undefined; + } +}; diff --git a/src/internal/shims/nullGetBuiltinModule.ts b/src/internal/shims/nullGetBuiltinModule.ts new file mode 100644 index 0000000..8bd2280 --- /dev/null +++ b/src/internal/shims/nullGetBuiltinModule.ts @@ -0,0 +1 @@ +export const getBuiltinModule = null; diff --git a/src/internal/to-file.ts b/src/internal/to-file.ts new file mode 100644 index 0000000..e92ac69 --- /dev/null +++ b/src/internal/to-file.ts @@ -0,0 +1,152 @@ +import { type File, getFile } from './shims/file'; +import { BlobPart, getName, makeFile, isAsyncIterable } from './uploads'; +import type { FilePropertyBag } from './builtin-types'; + +type BlobLikePart = string | ArrayBuffer | ArrayBufferView | BlobLike | DataView; + +/** + * Intended to match DOM Blob, node-fetch Blob, node:buffer Blob, etc. + * Don't add arrayBuffer here, node-fetch doesn't have it + */ +interface BlobLike { + /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Blob/size) */ + readonly size: number; + /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Blob/type) */ + readonly type: string; + /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Blob/text) */ + text(): Promise<string>; + /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Blob/slice) */ + slice(start?: number, end?: number): BlobLike; +} + +/** + * This check adds the arrayBuffer() method type because it is available and used at runtime + */ +const isBlobLike = (value: any): value is BlobLike & { arrayBuffer(): Promise<ArrayBuffer> } => + value != null && + typeof value === 'object' && + typeof value.size === 'number' && + typeof value.type === 'string' && + typeof value.text === 'function' && + typeof value.slice === 'function' && + typeof value.arrayBuffer === 'function'; + +/** + * Intended to match DOM File, node:buffer File, undici File, etc. + */ +interface FileLike extends BlobLike { + /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/File/lastModified) */ + readonly lastModified: number; + /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/File/name) */ + readonly name?: string | undefined; +} + +/** + * This check adds the arrayBuffer() method type because it is available and used at runtime + */ +const isFileLike = (value: any): value is FileLike & { arrayBuffer(): Promise<ArrayBuffer> } => + value != null && + typeof value === 'object' && + typeof value.name === 'string' && + typeof value.lastModified === 'number' && + isBlobLike(value); + +/** + * Intended to match DOM Response, node-fetch Response, undici Response, etc. + */ +export interface ResponseLike { + url: string; + blob(): Promise<BlobLike>; +} + +const isResponseLike = (value: any): value is ResponseLike => + value != null && + typeof value === 'object' && + typeof value.url === 'string' && + typeof value.blob === 'function'; + +export type ToFileInput = + | FileLike + | ResponseLike + | Exclude<BlobLikePart, string> + | AsyncIterable<BlobLikePart>; + +/** + * Helper for creating a {@link File} to pass to an SDK upload method from a variety of different data formats + * @param value the raw content of the file. Can be an {@link Uploadable}, {@link BlobLikePart}, or {@link AsyncIterable} of {@link BlobLikePart}s + * @param {string=} name the name of the file. If omitted, toFile will try to determine a file name from bits if possible + * @param {Object=} options additional properties + * @param {string=} options.type the MIME type of the content + * @param {number=} options.lastModified the last modified timestamp + * @returns a {@link File} with the given properties + */ +export async function toFile( + value: ToFileInput | PromiseLike<ToFileInput>, + name?: string | null | undefined, + options?: FilePropertyBag | undefined, +): Promise<File> { + // If it's a promise, resolve it. + value = await value; + + // If we've been given a `File` we don't need to do anything + if (isFileLike(value)) { + if (value instanceof getFile()) { + return value; + } + return makeFile([await value.arrayBuffer()], value.name); + } + + if (isResponseLike(value)) { + const blob = await value.blob(); + name ||= new URL(value.url).pathname.split(/[\\/]/).pop(); + + return makeFile(await getBytes(blob), name, options); + } + + const parts = await getBytes(value); + + name ||= getName(value); + + if (!options?.type) { + const type = parts.find((part) => typeof part === 'object' && 'type' in part && part.type); + if (typeof type === 'string') { + options = { ...options, type }; + } + } + + return makeFile(parts, name, options); +} + +async function getBytes(value: BlobLikePart | AsyncIterable<BlobLikePart>): Promise<Array<BlobPart>> { + let parts: Array<BlobPart> = []; + if ( + typeof value === 'string' || + ArrayBuffer.isView(value) || // includes Uint8Array, Buffer, etc. + value instanceof ArrayBuffer + ) { + parts.push(value); + } else if (isBlobLike(value)) { + parts.push(value instanceof Blob ? value : await value.arrayBuffer()); + } else if ( + isAsyncIterable(value) // includes Readable, ReadableStream, etc. + ) { + for await (const chunk of value) { + parts.push(...(await getBytes(chunk as BlobLikePart))); // TODO, consider validating? + } + } else { + const constructor = value?.constructor?.name; + throw new Error( + `Unexpected data type: ${typeof value}${ + constructor ? `; constructor: ${constructor}` : '' + }${propsForError(value)}`, + ); + } + + return parts; +} + +function propsForError(value: unknown): string { + if (typeof value !== 'object' || value === null) return ''; + const props = Object.getOwnPropertyNames(value); + return `; props: [${props.map((p) => `"${p}"`).join(', ')}]`; +} diff --git a/src/internal/types.ts b/src/internal/types.ts new file mode 100644 index 0000000..d7928cd --- /dev/null +++ b/src/internal/types.ts @@ -0,0 +1,92 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export type PromiseOrValue<T> = T | Promise<T>; +export type HTTPMethod = 'get' | 'post' | 'put' | 'patch' | 'delete'; + +export type KeysEnum<T> = { [P in keyof Required<T>]: true }; + +export type FinalizedRequestInit = RequestInit & { headers: Headers }; + +type NotAny<T> = [unknown] extends [T] ? never : T; + +/** + * Some environments overload the global fetch function, and Parameters<T> only gets the last signature. + */ +type OverloadedParameters<T> = + T extends ( + { + (...args: infer A): unknown; + (...args: infer B): unknown; + (...args: infer C): unknown; + (...args: infer D): unknown; + } + ) ? + A | B | C | D + : T extends ( + { + (...args: infer A): unknown; + (...args: infer B): unknown; + (...args: infer C): unknown; + } + ) ? + A | B | C + : T extends ( + { + (...args: infer A): unknown; + (...args: infer B): unknown; + } + ) ? + A | B + : T extends (...args: infer A) => unknown ? A + : never; + +/* eslint-disable */ +/** + * These imports attempt to get types from a parent package's dependencies. + * Unresolved bare specifiers can trigger [automatic type acquisition][1] in some projects, which + * would cause typescript to show types not present at runtime. To avoid this, we import + * directly from parent node_modules folders. + * + * We need to check multiple levels because we don't know what directory structure we'll be in. + * For example, pnpm generates directories like this: + * ``` + * node_modules + * ├── .pnpm + * │ └── pkg@1.0.0 + * │ └── node_modules + * │ └── pkg + * │ └── internal + * │ └── types.d.ts + * ├── pkg -> .pnpm/pkg@1.0.0/node_modules/pkg + * └── undici + * ``` + * + * [1]: https://www.typescriptlang.org/tsconfig/#typeAcquisition + */ +/** @ts-ignore For users with \@types/node */ +type UndiciTypesRequestInit = NotAny<import('../node_modules/undici-types').RequestInit> | NotAny<import('../../node_modules/undici-types').RequestInit> | NotAny<import('../../../node_modules/undici-types').RequestInit> | NotAny<import('../../../../node_modules/undici-types').RequestInit> | NotAny<import('../../../../../node_modules/undici-types').RequestInit> | NotAny<import('../../../../../../node_modules/undici-types').RequestInit> | NotAny<import('../../../../../../../node_modules/undici-types').RequestInit> | NotAny<import('../../../../../../../../node_modules/undici-types').RequestInit> | NotAny<import('../../../../../../../../../node_modules/undici-types').RequestInit> | NotAny<import('../../../../../../../../../../node_modules/undici-types').RequestInit>; +/** @ts-ignore For users with undici */ +type UndiciRequestInit = NotAny<import('../node_modules/undici').RequestInit> | NotAny<import('../../node_modules/undici').RequestInit> | NotAny<import('../../../node_modules/undici').RequestInit> | NotAny<import('../../../../node_modules/undici').RequestInit> | NotAny<import('../../../../../node_modules/undici').RequestInit> | NotAny<import('../../../../../../node_modules/undici').RequestInit> | NotAny<import('../../../../../../../node_modules/undici').RequestInit> | NotAny<import('../../../../../../../../node_modules/undici').RequestInit> | NotAny<import('../../../../../../../../../node_modules/undici').RequestInit> | NotAny<import('../../../../../../../../../../node_modules/undici').RequestInit>; +/** @ts-ignore For users with \@types/bun */ +type BunRequestInit = globalThis.FetchRequestInit; +/** @ts-ignore For users with node-fetch */ +type NodeFetchRequestInit = NotAny<import('../node_modules/node-fetch').RequestInit> | NotAny<import('../../node_modules/node-fetch').RequestInit> | NotAny<import('../../../node_modules/node-fetch').RequestInit> | NotAny<import('../../../../node_modules/node-fetch').RequestInit> | NotAny<import('../../../../../node_modules/node-fetch').RequestInit> | NotAny<import('../../../../../../node_modules/node-fetch').RequestInit> | NotAny<import('../../../../../../../node_modules/node-fetch').RequestInit> | NotAny<import('../../../../../../../../node_modules/node-fetch').RequestInit> | NotAny<import('../../../../../../../../../node_modules/node-fetch').RequestInit> | NotAny<import('../../../../../../../../../../node_modules/node-fetch').RequestInit>; +/** @ts-ignore For users who use Deno */ +type FetchRequestInit = NonNullable<OverloadedParameters<typeof fetch>[1]>; +/* eslint-enable */ + +type RequestInits = + | NotAny<UndiciTypesRequestInit> + | NotAny<UndiciRequestInit> + | NotAny<BunRequestInit> + | NotAny<NodeFetchRequestInit> + | NotAny<RequestInit> + | NotAny<FetchRequestInit>; + +/** + * This type contains `RequestInit` options that may be available on the current runtime, + * including per-platform extensions like `dispatcher`, `agent`, `client`, etc. + */ +export type MergedRequestInit = RequestInits & + /** We don't include these in the types as they'll be overridden for every request. */ + Partial<Record<'body' | 'headers' | 'method' | 'signal', never>>; diff --git a/src/internal/uploads.ts b/src/internal/uploads.ts new file mode 100644 index 0000000..fa0627a --- /dev/null +++ b/src/internal/uploads.ts @@ -0,0 +1,175 @@ +import { type RequestOptions } from './request-options'; +import type { FilePropertyBag, Fetch } from './builtin-types'; +import type { Gitpod } from '../client'; +import { type File, getFile } from './shims/file'; +import { ReadableStreamFrom } from './shims'; + +export type BlobPart = string | ArrayBuffer | ArrayBufferView | Blob | DataView; +type FsReadStream = AsyncIterable<Uint8Array> & { path: string | { toString(): string } }; + +// https://github.com/oven-sh/bun/issues/5980 +interface BunFile extends Blob { + readonly name?: string | undefined; +} + +/** + * Typically, this is a native "File" class. + * + * We provide the {@link toFile} utility to convert a variety of objects + * into the File class. + * + * For convenience, you can also pass a fetch Response, or in Node, + * the result of fs.createReadStream(). + */ +export type Uploadable = File | Response | FsReadStream | BunFile; + +/** + * Construct a `File` instance. This is used to ensure a helpful error is thrown + * for environments that don't define a global `File` yet. + */ +export function makeFile( + fileBits: BlobPart[], + fileName: string | undefined, + options?: FilePropertyBag, +): File { + const File = getFile(); + return new File(fileBits as any, fileName ?? 'unknown_file', options); +} + +export function getName(value: any): string | undefined { + return ( + ( + (typeof value === 'object' && + value !== null && + (('name' in value && value.name && String(value.name)) || + ('url' in value && value.url && String(value.url)) || + ('filename' in value && value.filename && String(value.filename)) || + ('path' in value && value.path && String(value.path)))) || + '' + ) + .split(/[\\/]/) + .pop() || undefined + ); +} + +export const isAsyncIterable = (value: any): value is AsyncIterable<any> => + value != null && typeof value === 'object' && typeof value[Symbol.asyncIterator] === 'function'; + +/** + * Returns a multipart/form-data request if any part of the given request body contains a File / Blob value. + * Otherwise returns the request as is. + */ +export const maybeMultipartFormRequestOptions = async ( + opts: RequestOptions, + fetch: Gitpod | Fetch, +): Promise<RequestOptions> => { + if (!hasUploadableValue(opts.body)) return opts; + + return { ...opts, body: await createForm(opts.body, fetch) }; +}; + +type MultipartFormRequestOptions = Omit<RequestOptions, 'body'> & { body: unknown }; + +export const multipartFormRequestOptions = async ( + opts: MultipartFormRequestOptions, + fetch: Gitpod | Fetch, +): Promise<RequestOptions> => { + return { ...opts, body: await createForm(opts.body, fetch) }; +}; + +const supportsFormDataMap = new WeakMap<Fetch, Promise<boolean>>(); + +/** + * node-fetch doesn't support the global FormData object in recent node versions. Instead of sending + * properly-encoded form data, it just stringifies the object, resulting in a request body of "[object FormData]". + * This function detects if the fetch function provided supports the global FormData object to avoid + * confusing error messages later on. + */ +function supportsFormData(fetchObject: Gitpod | Fetch): Promise<boolean> { + const fetch: Fetch = typeof fetchObject === 'function' ? fetchObject : (fetchObject as any).fetch; + const cached = supportsFormDataMap.get(fetch); + if (cached) return cached; + const promise = (async () => { + try { + const FetchResponse = ( + 'Response' in fetch ? + fetch.Response + : (await fetch('data:,')).constructor) as typeof Response; + const data = new FormData(); + if (data.toString() === (await new FetchResponse(data).text())) { + return false; + } + return true; + } catch { + // avoid false negatives + return true; + } + })(); + supportsFormDataMap.set(fetch, promise); + return promise; +} + +export const createForm = async <T = Record<string, unknown>>( + body: T | undefined, + fetch: Gitpod | Fetch, +): Promise<FormData> => { + if (!(await supportsFormData(fetch))) { + throw new TypeError( + 'The provided fetch function does not support file uploads with the current global FormData class.', + ); + } + const form = new FormData(); + await Promise.all(Object.entries(body || {}).map(([key, value]) => addFormValue(form, key, value))); + return form; +}; + +// We check for Blob not File because Bun.File doesn't inherit from File, +// but they both inherit from Blob and have a `name` property at runtime. +const isNamedBlob = (value: object) => + value instanceof getFile() || (value instanceof Blob && 'name' in value); + +const isUploadable = (value: unknown) => + typeof value === 'object' && + value !== null && + (value instanceof Response || isAsyncIterable(value) || isNamedBlob(value)); + +const hasUploadableValue = (value: unknown): boolean => { + if (isUploadable(value)) return true; + if (Array.isArray(value)) return value.some(hasUploadableValue); + if (value && typeof value === 'object') { + for (const k in value) { + if (hasUploadableValue((value as any)[k])) return true; + } + } + return false; +}; + +const addFormValue = async (form: FormData, key: string, value: unknown): Promise<void> => { + if (value === undefined) return; + if (value == null) { + throw new TypeError( + `Received null for "${key}"; to pass null in FormData, you must use the string 'null'`, + ); + } + + // TODO: make nested formats configurable + if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') { + form.append(key, String(value)); + } else if (value instanceof Response) { + form.append(key, makeFile([await value.blob()], getName(value))); + } else if (isAsyncIterable(value)) { + form.append(key, makeFile([await new Response(ReadableStreamFrom(value)).blob()], getName(value))); + } else if (isNamedBlob(value)) { + form.append(key, value, getName(value)); + } else if (Array.isArray(value)) { + await Promise.all(value.map((entry) => addFormValue(form, key + '[]', entry))); + } else if (typeof value === 'object') { + await Promise.all( + Object.entries(value).map(([name, prop]) => addFormValue(form, `${key}[${name}]`, prop)), + ); + } else { + throw new TypeError( + `Invalid value given to form, expected a string, number, boolean, object, Array, File or Blob but got ${value} instead`, + ); + } +}; diff --git a/src/internal/utils.ts b/src/internal/utils.ts new file mode 100644 index 0000000..3cbfacc --- /dev/null +++ b/src/internal/utils.ts @@ -0,0 +1,8 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export * from './utils/values'; +export * from './utils/base64'; +export * from './utils/env'; +export * from './utils/log'; +export * from './utils/uuid'; +export * from './utils/sleep'; diff --git a/src/internal/utils/base64.ts b/src/internal/utils/base64.ts new file mode 100644 index 0000000..04d8296 --- /dev/null +++ b/src/internal/utils/base64.ts @@ -0,0 +1,40 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { GitpodError } from '../../core/error'; +import { encodeUTF8 } from './bytes'; + +export const toBase64 = (data: string | Uint8Array | null | undefined): string => { + if (!data) return ''; + + if (typeof (globalThis as any).Buffer !== 'undefined') { + return (globalThis as any).Buffer.from(data).toString('base64'); + } + + if (typeof data === 'string') { + data = encodeUTF8(data); + } + + if (typeof btoa !== 'undefined') { + return btoa(String.fromCharCode.apply(null, data as any)); + } + + throw new GitpodError('Cannot generate base64 string; Expected `Buffer` or `btoa` to be defined'); +}; + +export const fromBase64 = (str: string): Uint8Array => { + if (typeof (globalThis as any).Buffer !== 'undefined') { + const buf = (globalThis as any).Buffer.from(str, 'base64'); + return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength); + } + + if (typeof atob !== 'undefined') { + const bstr = atob(str); + const buf = new Uint8Array(bstr.length); + for (let i = 0; i < bstr.length; i++) { + buf[i] = bstr.charCodeAt(i); + } + return buf; + } + + throw new GitpodError('Cannot decode base64 string; Expected `Buffer` or `atob` to be defined'); +}; diff --git a/src/internal/utils/bytes.ts b/src/internal/utils/bytes.ts new file mode 100644 index 0000000..8da627a --- /dev/null +++ b/src/internal/utils/bytes.ts @@ -0,0 +1,32 @@ +export function concatBytes(buffers: Uint8Array[]): Uint8Array { + let length = 0; + for (const buffer of buffers) { + length += buffer.length; + } + const output = new Uint8Array(length); + let index = 0; + for (const buffer of buffers) { + output.set(buffer, index); + index += buffer.length; + } + + return output; +} + +let encodeUTF8_: (str: string) => Uint8Array; +export function encodeUTF8(str: string) { + let encoder; + return ( + encodeUTF8_ ?? + ((encoder = new (globalThis as any).TextEncoder()), (encodeUTF8_ = encoder.encode.bind(encoder))) + )(str); +} + +let decodeUTF8_: (bytes: Uint8Array) => string; +export function decodeUTF8(bytes: Uint8Array) { + let decoder; + return ( + decodeUTF8_ ?? + ((decoder = new (globalThis as any).TextDecoder()), (decodeUTF8_ = decoder.decode.bind(decoder))) + )(bytes); +} diff --git a/src/internal/utils/env.ts b/src/internal/utils/env.ts new file mode 100644 index 0000000..2d84800 --- /dev/null +++ b/src/internal/utils/env.ts @@ -0,0 +1,18 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +/** + * Read an environment variable. + * + * Trims beginning and trailing whitespace. + * + * Will return undefined if the environment variable doesn't exist or cannot be accessed. + */ +export const readEnv = (env: string): string | undefined => { + if (typeof (globalThis as any).process !== 'undefined') { + return (globalThis as any).process.env?.[env]?.trim() ?? undefined; + } + if (typeof (globalThis as any).Deno !== 'undefined') { + return (globalThis as any).Deno.env?.get?.(env)?.trim(); + } + return undefined; +}; diff --git a/src/internal/utils/log.ts b/src/internal/utils/log.ts new file mode 100644 index 0000000..8fdf60d --- /dev/null +++ b/src/internal/utils/log.ts @@ -0,0 +1,126 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { hasOwn } from './values'; +import { type Gitpod } from '../../client'; +import { RequestOptions } from '../request-options'; + +type LogFn = (message: string, ...rest: unknown[]) => void; +export type Logger = { + error: LogFn; + warn: LogFn; + info: LogFn; + debug: LogFn; +}; +export type LogLevel = 'off' | 'error' | 'warn' | 'info' | 'debug'; + +const levelNumbers = { + off: 0, + error: 200, + warn: 300, + info: 400, + debug: 500, +}; + +export const parseLogLevel = ( + maybeLevel: string | undefined, + sourceName: string, + client: Gitpod, +): LogLevel | undefined => { + if (!maybeLevel) { + return undefined; + } + if (hasOwn(levelNumbers, maybeLevel)) { + return maybeLevel; + } + loggerFor(client).warn( + `${sourceName} was set to ${JSON.stringify(maybeLevel)}, expected one of ${JSON.stringify( + Object.keys(levelNumbers), + )}`, + ); + return undefined; +}; + +function noop() {} + +function makeLogFn(fnLevel: keyof Logger, logger: Logger | undefined, logLevel: LogLevel) { + if (!logger || levelNumbers[fnLevel] > levelNumbers[logLevel]) { + return noop; + } else { + // Don't wrap logger functions, we want the stacktrace intact! + return logger[fnLevel].bind(logger); + } +} + +const noopLogger = { + error: noop, + warn: noop, + info: noop, + debug: noop, +}; + +let cachedLoggers = new WeakMap<Logger, [LogLevel, Logger]>(); + +export function loggerFor(client: Gitpod): Logger { + const logger = client.logger; + const logLevel = client.logLevel ?? 'off'; + if (!logger) { + return noopLogger; + } + + const cachedLogger = cachedLoggers.get(logger); + if (cachedLogger && cachedLogger[0] === logLevel) { + return cachedLogger[1]; + } + + const levelLogger = { + error: makeLogFn('error', logger, logLevel), + warn: makeLogFn('warn', logger, logLevel), + info: makeLogFn('info', logger, logLevel), + debug: makeLogFn('debug', logger, logLevel), + }; + + cachedLoggers.set(logger, [logLevel, levelLogger]); + + return levelLogger; +} + +export const formatRequestDetails = (details: { + options?: RequestOptions | undefined; + headers?: Headers | Record<string, string> | undefined; + retryOfRequestLogID?: string | undefined; + retryOf?: string | undefined; + url?: string | undefined; + status?: number | undefined; + method?: string | undefined; + durationMs?: number | undefined; + message?: unknown; + body?: unknown; +}) => { + if (details.options) { + details.options = { ...details.options }; + delete details.options['headers']; // redundant + leaks internals + } + if (details.headers) { + details.headers = Object.fromEntries( + (details.headers instanceof Headers ? [...details.headers] : Object.entries(details.headers)).map( + ([name, value]) => [ + name, + ( + name.toLowerCase() === 'authorization' || + name.toLowerCase() === 'cookie' || + name.toLowerCase() === 'set-cookie' + ) ? + '***' + : value, + ], + ), + ); + } + if ('retryOfRequestLogID' in details) { + if (details.retryOfRequestLogID) { + details.retryOf = details.retryOfRequestLogID; + } + delete details.retryOfRequestLogID; + } + return details; +}; diff --git a/src/internal/utils/path.ts b/src/internal/utils/path.ts new file mode 100644 index 0000000..56154a2 --- /dev/null +++ b/src/internal/utils/path.ts @@ -0,0 +1,63 @@ +import { GitpodError } from '../../core/error'; + +/** + * Percent-encode everything that isn't safe to have in a path without encoding safe chars. + * + * Taken from https://datatracker.ietf.org/doc/html/rfc3986#section-3.3: + * > unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~" + * > sub-delims = "!" / "$" / "&" / "'" / "(" / ")" / "*" / "+" / "," / ";" / "=" + * > pchar = unreserved / pct-encoded / sub-delims / ":" / "@" + */ +export function encodeURIPath(str: string) { + return str.replace(/[^A-Za-z0-9\-._~!$&'()*+,;=:@]+/g, encodeURIComponent); +} + +export const createPathTagFunction = (pathEncoder = encodeURIPath) => + function path(statics: readonly string[], ...params: readonly unknown[]): string { + // If there are no params, no processing is needed. + if (statics.length === 1) return statics[0]!; + + let postPath = false; + const path = statics.reduce((previousValue, currentValue, index) => { + if (/[?#]/.test(currentValue)) { + postPath = true; + } + return ( + previousValue + + currentValue + + (index === params.length ? '' : (postPath ? encodeURIComponent : pathEncoder)(String(params[index]))) + ); + }, ''); + + const pathOnly = path.split(/[?#]/, 1)[0]!; + const invalidSegments = []; + const invalidSegmentPattern = /(?<=^|\/)(?:\.|%2e){1,2}(?=\/|$)/gi; + let match; + + // Find all invalid segments + while ((match = invalidSegmentPattern.exec(pathOnly)) !== null) { + invalidSegments.push({ + start: match.index, + length: match[0].length, + }); + } + + if (invalidSegments.length > 0) { + let lastEnd = 0; + const underline = invalidSegments.reduce((acc, segment) => { + const spaces = ' '.repeat(segment.start - lastEnd); + const arrows = '^'.repeat(segment.length); + lastEnd = segment.start + segment.length; + return acc + spaces + arrows; + }, ''); + + throw new GitpodError(`Path parameters result in path with invalid segments:\n${path}\n${underline}`); + } + + return path; + }; + +/** + * URI-encodes path params and ensures no unsafe /./ or /../ path segments are introduced. + */ +export const path = createPathTagFunction(encodeURIPath); diff --git a/src/internal/utils/sleep.ts b/src/internal/utils/sleep.ts new file mode 100644 index 0000000..65e5296 --- /dev/null +++ b/src/internal/utils/sleep.ts @@ -0,0 +1,3 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export const sleep = (ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms)); diff --git a/src/internal/utils/uuid.ts b/src/internal/utils/uuid.ts new file mode 100644 index 0000000..5a262c6 --- /dev/null +++ b/src/internal/utils/uuid.ts @@ -0,0 +1,19 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { getCrypto } from '../shims/crypto'; + +/** + * https://stackoverflow.com/a/2117523 + */ +export let uuid4 = function () { + const crypto = getCrypto(); + if (crypto?.randomUUID) { + uuid4 = crypto.randomUUID.bind(crypto); + return crypto.randomUUID(); + } + const u8 = new Uint8Array(1); + const randomByte = crypto ? () => crypto.getRandomValues(u8)[0]! : () => (Math.random() * 0xff) & 0xff; + return '10000000-1000-4000-8000-100000000000'.replace(/[018]/g, (c) => + (+c ^ (randomByte() & (15 >> (+c / 4)))).toString(16), + ); +}; diff --git a/src/internal/utils/values.ts b/src/internal/utils/values.ts new file mode 100644 index 0000000..d0e9c61 --- /dev/null +++ b/src/internal/utils/values.ts @@ -0,0 +1,102 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { GitpodError } from '../../core/error'; + +// https://url.spec.whatwg.org/#url-scheme-string +const startsWithSchemeRegexp = /^[a-z][a-z0-9+.-]*:/i; + +export const isAbsoluteURL = (url: string): boolean => { + return startsWithSchemeRegexp.test(url); +}; + +/** Returns an object if the given value isn't an object, otherwise returns as-is */ +export function maybeObj(x: unknown): object { + if (typeof x !== 'object') { + return {}; + } + + return x ?? {}; +} + +// https://stackoverflow.com/a/34491287 +export function isEmptyObj(obj: Object | null | undefined): boolean { + if (!obj) return true; + for (const _k in obj) return false; + return true; +} + +// https://eslint.org/docs/latest/rules/no-prototype-builtins +export function hasOwn<T extends object = object>(obj: T, key: PropertyKey): key is keyof T { + return Object.prototype.hasOwnProperty.call(obj, key); +} + +export function isObj(obj: unknown): obj is Record<string, unknown> { + return obj != null && typeof obj === 'object' && !Array.isArray(obj); +} + +export const ensurePresent = <T>(value: T | null | undefined): T => { + if (value == null) { + throw new GitpodError(`Expected a value to be given but received ${value} instead.`); + } + + return value; +}; + +export const validatePositiveInteger = (name: string, n: unknown): number => { + if (typeof n !== 'number' || !Number.isInteger(n)) { + throw new GitpodError(`${name} must be an integer`); + } + if (n < 0) { + throw new GitpodError(`${name} must be a positive integer`); + } + return n; +}; + +export const coerceInteger = (value: unknown): number => { + if (typeof value === 'number') return Math.round(value); + if (typeof value === 'string') return parseInt(value, 10); + + throw new GitpodError(`Could not coerce ${value} (type: ${typeof value}) into a number`); +}; + +export const coerceFloat = (value: unknown): number => { + if (typeof value === 'number') return value; + if (typeof value === 'string') return parseFloat(value); + + throw new GitpodError(`Could not coerce ${value} (type: ${typeof value}) into a number`); +}; + +export const coerceBoolean = (value: unknown): boolean => { + if (typeof value === 'boolean') return value; + if (typeof value === 'string') return value === 'true'; + return Boolean(value); +}; + +export const maybeCoerceInteger = (value: unknown): number | undefined => { + if (value === undefined) { + return undefined; + } + return coerceInteger(value); +}; + +export const maybeCoerceFloat = (value: unknown): number | undefined => { + if (value === undefined) { + return undefined; + } + return coerceFloat(value); +}; + +export const maybeCoerceBoolean = (value: unknown): boolean | undefined => { + if (value === undefined) { + return undefined; + } + return coerceBoolean(value); +}; + +export const safeJSON = (text: string) => { + try { + return JSON.parse(text); + } catch (err) { + return undefined; + } +}; diff --git a/src/lib/.keep b/src/lib/.keep new file mode 100644 index 0000000..7554f8b --- /dev/null +++ b/src/lib/.keep @@ -0,0 +1,4 @@ +File generated from our OpenAPI spec by Stainless. + +This directory can be used to store custom files to expand the SDK. +It is ignored by Stainless code generation and its content (other than this keep file) won't be touched. diff --git a/src/pagination.ts b/src/pagination.ts new file mode 100644 index 0000000..90bf015 --- /dev/null +++ b/src/pagination.ts @@ -0,0 +1,2 @@ +/** @deprecated Import from ./core/pagination instead */ +export * from './core/pagination'; diff --git a/src/resource.ts b/src/resource.ts new file mode 100644 index 0000000..363e351 --- /dev/null +++ b/src/resource.ts @@ -0,0 +1,2 @@ +/** @deprecated Import from ./core/resource instead */ +export * from './core/resource'; diff --git a/src/resources.ts b/src/resources.ts new file mode 100644 index 0000000..b283d57 --- /dev/null +++ b/src/resources.ts @@ -0,0 +1 @@ +export * from './resources/index'; diff --git a/src/resources/accounts.ts b/src/resources/accounts.ts new file mode 100644 index 0000000..b341c47 --- /dev/null +++ b/src/resources/accounts.ts @@ -0,0 +1,499 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../core/resource'; +import * as Shared from './shared'; +import { APIPromise } from '../core/api-promise'; +import { LoginProvidersPage, type LoginProvidersPageParams, PagePromise } from '../core/pagination'; +import { RequestOptions } from '../internal/request-options'; + +export class Accounts extends APIResource { + /** + * Gets information about the currently authenticated account. + * + * Use this method to: + * + * - Retrieve account profile information + * - Check organization memberships + * - View account settings + * - Get joinable organizations + * + * ### Examples + * + * - Get account details: + * + * Retrieves information about the authenticated account. + * + * ```yaml + * {} + * ``` + */ + retrieve(body: AccountRetrieveParams, options?: RequestOptions): APIPromise<AccountRetrieveResponse> { + return this._client.post('/gitpod.v1.AccountService/GetAccount', { body, ...options }); + } + + /** + * Deletes an account permanently. + * + * Use this method to: + * + * - Remove unused accounts + * - Clean up test accounts + * - Complete account deletion requests + * + * The account must not be an active member of any organization. + * + * ### Examples + * + * - Delete account: + * + * Permanently removes an account. + * + * ```yaml + * accountId: "f53d2330-3795-4c5d-a1f3-453121af9c60" + * ``` + */ + delete(body: AccountDeleteParams, options?: RequestOptions): APIPromise<unknown> { + return this._client.post('/gitpod.v1.AccountService/DeleteAccount', { body, ...options }); + } + + /** + * Gets the SSO login URL for a specific email domain. + * + * Use this method to: + * + * - Initiate SSO authentication + * - Get organization-specific login URLs + * - Handle SSO redirects + * + * ### Examples + * + * - Get login URL: + * + * Retrieves SSO URL for email domain. + * + * ```yaml + * email: "user@company.com" + * ``` + * + * - Get URL with return path: + * + * Gets SSO URL with specific return location. + * + * ```yaml + * email: "user@company.com" + * returnTo: "https://gitpod.io/workspaces" + * ``` + */ + getSSOLoginURL( + body: AccountGetSSOLoginURLParams, + options?: RequestOptions, + ): APIPromise<AccountGetSSOLoginURLResponse> { + return this._client.post('/gitpod.v1.AccountService/GetSSOLoginURL', { body, ...options }); + } + + /** + * Lists available login providers with optional filtering. + * + * Use this method to: + * + * - View supported authentication methods + * - Get provider-specific login URLs + * - Filter providers by invite + * + * ### Examples + * + * - List all providers: + * + * Shows all available login providers. + * + * ```yaml + * pagination: + * pageSize: 20 + * ``` + * + * - List for specific invite: + * + * Shows providers available for an invite. + * + * ```yaml + * filter: + * inviteId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + * pagination: + * pageSize: 20 + * ``` + */ + listLoginProviders( + params: AccountListLoginProvidersParams, + options?: RequestOptions, + ): PagePromise<LoginProvidersLoginProvidersPage, LoginProvider> { + const { token, pageSize, ...body } = params; + return this._client.getAPIList( + '/gitpod.v1.AccountService/ListLoginProviders', + LoginProvidersPage<LoginProvider>, + { query: { token, pageSize }, body, method: 'post', ...options }, + ); + } +} + +export type LoginProvidersLoginProvidersPage = LoginProvidersPage<LoginProvider>; + +export interface Account { + id: string; + + /** + * A Timestamp represents a point in time independent of any time zone or local + * calendar, encoded as a count of seconds and fractions of seconds at nanosecond + * resolution. The count is relative to an epoch at UTC midnight on January 1, + * 1970, in the proleptic Gregorian calendar which extends the Gregorian calendar + * backwards to year one. + * + * All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap + * second table is needed for interpretation, using a + * [24-hour linear smear](https://developers.google.com/time/smear). + * + * The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By + * restricting to that range, we ensure that we can convert to and from + * [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. + * + * # Examples + * + * Example 1: Compute Timestamp from POSIX `time()`. + * + * Timestamp timestamp; + * timestamp.set_seconds(time(NULL)); + * timestamp.set_nanos(0); + * + * Example 2: Compute Timestamp from POSIX `gettimeofday()`. + * + * struct timeval tv; + * gettimeofday(&tv, NULL); + * + * Timestamp timestamp; + * timestamp.set_seconds(tv.tv_sec); + * timestamp.set_nanos(tv.tv_usec * 1000); + * + * Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. + * + * FILETIME ft; + * GetSystemTimeAsFileTime(&ft); + * UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; + * + * // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z + * // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. + * Timestamp timestamp; + * timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); + * timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); + * + * Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. + * + * long millis = System.currentTimeMillis(); + * + * Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) + * .setNanos((int) ((millis % 1000) * 1000000)).build(); + * + * Example 5: Compute Timestamp from Java `Instant.now()`. + * + * Instant now = Instant.now(); + * + * Timestamp timestamp = + * Timestamp.newBuilder().setSeconds(now.getEpochSecond()) + * .setNanos(now.getNano()).build(); + * + * Example 6: Compute Timestamp from current time in Python. + * + * timestamp = Timestamp() + * timestamp.GetCurrentTime() + * + * # JSON Mapping + * + * In JSON format, the Timestamp type is encoded as a string in the + * [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the format is + * "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" where {year} is always + * expressed using four digits while {month}, {day}, {hour}, {min}, and {sec} are + * zero-padded to two digits each. The fractional seconds, which can go up to 9 + * digits (i.e. up to 1 nanosecond resolution), are optional. The "Z" suffix + * indicates the timezone ("UTC"); the timezone is required. A proto3 JSON + * serializer should always use UTC (as indicated by "Z") when printing the + * Timestamp type and a proto3 JSON parser should be able to accept both UTC and + * other timezones (as indicated by an offset). + * + * For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past 01:30 UTC on + * January 15, 2017. + * + * In JavaScript, one can convert a Date object to this format using the standard + * [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) + * method. In Python, a standard `datetime.datetime` object can be converted to + * this format using + * [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with the + * time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use the + * Joda Time's + * [`ISODateTimeFormat.dateTime()`](<http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime()>) + * to obtain a formatter capable of generating timestamps in this format. + */ + createdAt: string; + + email: string; + + name: string; + + /** + * A Timestamp represents a point in time independent of any time zone or local + * calendar, encoded as a count of seconds and fractions of seconds at nanosecond + * resolution. The count is relative to an epoch at UTC midnight on January 1, + * 1970, in the proleptic Gregorian calendar which extends the Gregorian calendar + * backwards to year one. + * + * All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap + * second table is needed for interpretation, using a + * [24-hour linear smear](https://developers.google.com/time/smear). + * + * The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By + * restricting to that range, we ensure that we can convert to and from + * [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. + * + * # Examples + * + * Example 1: Compute Timestamp from POSIX `time()`. + * + * Timestamp timestamp; + * timestamp.set_seconds(time(NULL)); + * timestamp.set_nanos(0); + * + * Example 2: Compute Timestamp from POSIX `gettimeofday()`. + * + * struct timeval tv; + * gettimeofday(&tv, NULL); + * + * Timestamp timestamp; + * timestamp.set_seconds(tv.tv_sec); + * timestamp.set_nanos(tv.tv_usec * 1000); + * + * Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. + * + * FILETIME ft; + * GetSystemTimeAsFileTime(&ft); + * UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; + * + * // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z + * // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. + * Timestamp timestamp; + * timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); + * timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); + * + * Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. + * + * long millis = System.currentTimeMillis(); + * + * Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) + * .setNanos((int) ((millis % 1000) * 1000000)).build(); + * + * Example 5: Compute Timestamp from Java `Instant.now()`. + * + * Instant now = Instant.now(); + * + * Timestamp timestamp = + * Timestamp.newBuilder().setSeconds(now.getEpochSecond()) + * .setNanos(now.getNano()).build(); + * + * Example 6: Compute Timestamp from current time in Python. + * + * timestamp = Timestamp() + * timestamp.GetCurrentTime() + * + * # JSON Mapping + * + * In JSON format, the Timestamp type is encoded as a string in the + * [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the format is + * "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" where {year} is always + * expressed using four digits while {month}, {day}, {hour}, {min}, and {sec} are + * zero-padded to two digits each. The fractional seconds, which can go up to 9 + * digits (i.e. up to 1 nanosecond resolution), are optional. The "Z" suffix + * indicates the timezone ("UTC"); the timezone is required. A proto3 JSON + * serializer should always use UTC (as indicated by "Z") when printing the + * Timestamp type and a proto3 JSON parser should be able to accept both UTC and + * other timezones (as indicated by an offset). + * + * For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past 01:30 UTC on + * January 15, 2017. + * + * In JavaScript, one can convert a Date object to this format using the standard + * [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) + * method. In Python, a standard `datetime.datetime` object can be converted to + * this format using + * [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with the + * time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use the + * Joda Time's + * [`ISODateTimeFormat.dateTime()`](<http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime()>) + * to obtain a formatter capable of generating timestamps in this format. + */ + updatedAt: string; + + avatarUrl?: string; + + joinables?: Array<JoinableOrganization>; + + memberships?: Array<AccountMembership>; + + /** + * organization_id is the ID of the organization the account is owned by if it's + * created through custom SSO + */ + organizationId?: string | null; + + /** + * public_email_provider is true if the email for the Account matches a known + * public email provider + */ + publicEmailProvider?: boolean; +} + +export interface AccountMembership { + /** + * organization_id is the id of the organization the user is a member of + */ + organizationId: string; + + /** + * organization_name is the name of the organization the user is a member of + */ + organizationName: string; + + /** + * user_id is the ID the user has in the organization + */ + userId: string; + + /** + * user_role is the role the user has in the organization + */ + userRole: Shared.OrganizationRole; + + /** + * organization_name is the member count of the organization the user is a member + * of + */ + organizationMemberCount?: number; +} + +export interface JoinableOrganization { + /** + * organization_id is the id of the organization the user can join + */ + organizationId: string; + + /** + * organization_name is the name of the organization the user can join + */ + organizationName: string; + + /** + * organization_member_count is the member count of the organization the user can + * join + */ + organizationMemberCount?: number; +} + +export interface LoginProvider { + /** + * provider is the provider used by this login method, e.g. "github", "google", + * "custom" + */ + provider: string; + + /** + * login_url is the URL to redirect the browser agent to for login, when provider + * is "custom" + */ + loginUrl?: string; +} + +export interface AccountRetrieveResponse { + account: Account; +} + +export type AccountDeleteResponse = unknown; + +export interface AccountGetSSOLoginURLResponse { + /** + * login_url is the URL to redirect the user to for SSO login + */ + loginUrl: string; +} + +export interface AccountRetrieveParams { + empty?: boolean; +} + +export interface AccountDeleteParams { + accountId: string; +} + +export interface AccountGetSSOLoginURLParams { + /** + * email is the email the user wants to login with + */ + email: string; + + /** + * return_to is the URL the user will be redirected to after login + */ + returnTo?: string | null; +} + +export interface AccountListLoginProvidersParams extends LoginProvidersPageParams { + /** + * Body param: filter contains the filter options for listing login methods + */ + filter?: AccountListLoginProvidersParams.Filter; + + /** + * Body param: pagination contains the pagination options for listing login methods + */ + pagination?: AccountListLoginProvidersParams.Pagination; +} + +export namespace AccountListLoginProvidersParams { + /** + * filter contains the filter options for listing login methods + */ + export interface Filter { + /** + * invite_id is the ID of the invite URL the user wants to login with + */ + inviteId?: string; + } + + /** + * pagination contains the pagination options for listing login methods + */ + export interface Pagination { + /** + * Token for the next set of results that was returned as next_token of a + * PaginationResponse + */ + token?: string; + + /** + * Page size is the maximum number of results to retrieve per page. Defaults to 25. + * Maximum 100. + */ + pageSize?: number; + } +} + +export declare namespace Accounts { + export { + type Account as Account, + type AccountMembership as AccountMembership, + type JoinableOrganization as JoinableOrganization, + type LoginProvider as LoginProvider, + type AccountRetrieveResponse as AccountRetrieveResponse, + type AccountDeleteResponse as AccountDeleteResponse, + type AccountGetSSOLoginURLResponse as AccountGetSSOLoginURLResponse, + type LoginProvidersLoginProvidersPage as LoginProvidersLoginProvidersPage, + type AccountRetrieveParams as AccountRetrieveParams, + type AccountDeleteParams as AccountDeleteParams, + type AccountGetSSOLoginURLParams as AccountGetSSOLoginURLParams, + type AccountListLoginProvidersParams as AccountListLoginProvidersParams, + }; +} diff --git a/src/resources/editors.ts b/src/resources/editors.ts new file mode 100644 index 0000000..84853ac --- /dev/null +++ b/src/resources/editors.ts @@ -0,0 +1,210 @@ +// 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 { EditorsPage, type EditorsPageParams, PagePromise } from '../core/pagination'; +import { RequestOptions } from '../internal/request-options'; + +export class Editors extends APIResource { + /** + * Gets details about a specific editor. + * + * Use this method to: + * + * - View editor information + * - Get editor configuration + * + * ### Examples + * + * - Get editor details: + * + * Retrieves information about a specific editor. + * + * ```yaml + * id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + * ``` + */ + retrieve(body: EditorRetrieveParams, options?: RequestOptions): APIPromise<EditorRetrieveResponse> { + return this._client.post('/gitpod.v1.EditorService/GetEditor', { body, ...options }); + } + + /** + * Lists all available code editors, optionally filtered to those allowed in an + * organization. + * + * Use this method to: + * + * - View supported editors + * - Get editor capabilities + * - Browse editor options + * - Check editor availability + * + * ### Examples + * + * - List editors: + * + * Shows all available editors with pagination. + * + * ```yaml + * pagination: + * pageSize: 20 + * ``` + * + * - List editors available to the organization: + * + * Shows all available editors that are allowed by the policies enforced in the + * organization with pagination. + * + * ```yaml + * pagination: + * pageSize: 20 + * filter: + * allowedByPolicy: true + * ``` + */ + list(params: EditorListParams, options?: RequestOptions): PagePromise<EditorsEditorsPage, Editor> { + const { token, pageSize, ...body } = params; + return this._client.getAPIList('/gitpod.v1.EditorService/ListEditors', EditorsPage<Editor>, { + query: { token, pageSize }, + body, + method: 'post', + ...options, + }); + } + + /** + * Resolves the URL for accessing an editor in a specific environment. + * + * Use this method to: + * + * - Get editor access URLs + * - Launch editors for environments + * - Set up editor connections + * - Configure editor access + * + * ### Examples + * + * - Resolve editor URL: + * + * Gets the URL for accessing an editor in an environment. + * + * ```yaml + * editorId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + * environmentId: "07e03a28-65a5-4d98-b532-8ea67b188048" + * organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + * ``` + */ + resolveURL(body: EditorResolveURLParams, options?: RequestOptions): APIPromise<EditorResolveURLResponse> { + return this._client.post('/gitpod.v1.EditorService/ResolveEditorURL', { body, ...options }); + } +} + +export type EditorsEditorsPage = EditorsPage<Editor>; + +export interface Editor { + id: string; + + installationInstructions: string; + + name: string; + + urlTemplate: string; + + alias?: string; + + iconUrl?: string; + + shortDescription?: string; +} + +export interface EditorRetrieveResponse { + /** + * editor contains the editor + */ + editor: Editor; +} + +export interface EditorResolveURLResponse { + /** + * url is the resolved editor URL + */ + url: string; +} + +export interface EditorRetrieveParams { + /** + * id is the ID of the editor to get + */ + id: string; +} + +export interface EditorListParams extends EditorsPageParams { + /** + * Body param: filter contains the filter options for listing editors + */ + filter?: EditorListParams.Filter; + + /** + * Body param: pagination contains the pagination options for listing environments + */ + pagination?: EditorListParams.Pagination; +} + +export namespace EditorListParams { + /** + * filter contains the filter options for listing editors + */ + export interface Filter { + /** + * allowed_by_policy filters the response to only editors that are allowed by the + * policies enforced in the organization + */ + allowedByPolicy?: boolean; + } + + /** + * pagination contains the pagination options for listing environments + */ + export interface Pagination { + /** + * Token for the next set of results that was returned as next_token of a + * PaginationResponse + */ + token?: string; + + /** + * Page size is the maximum number of results to retrieve per page. Defaults to 25. + * Maximum 100. + */ + pageSize?: number; + } +} + +export interface EditorResolveURLParams { + /** + * editorId is the ID of the editor to resolve the URL for + */ + editorId: string; + + /** + * environmentId is the ID of the environment to resolve the URL for + */ + environmentId: string; + + /** + * organizationId is the ID of the organization to resolve the URL for + */ + organizationId: string; +} + +export declare namespace Editors { + export { + type Editor as Editor, + type EditorRetrieveResponse as EditorRetrieveResponse, + type EditorResolveURLResponse as EditorResolveURLResponse, + type EditorsEditorsPage as EditorsEditorsPage, + type EditorRetrieveParams as EditorRetrieveParams, + type EditorListParams as EditorListParams, + type EditorResolveURLParams as EditorResolveURLParams, + }; +} diff --git a/src/resources/environments.ts b/src/resources/environments.ts new file mode 100644 index 0000000..85fdba4 --- /dev/null +++ b/src/resources/environments.ts @@ -0,0 +1,3 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export * from './environments/index'; diff --git a/src/resources/environments/automations.ts b/src/resources/environments/automations.ts new file mode 100644 index 0000000..e13af42 --- /dev/null +++ b/src/resources/environments/automations.ts @@ -0,0 +1,3 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export * from './automations/index'; diff --git a/src/resources/environments/automations/automations.ts b/src/resources/environments/automations/automations.ts new file mode 100644 index 0000000..a369c3c --- /dev/null +++ b/src/resources/environments/automations/automations.ts @@ -0,0 +1,231 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../../../core/resource'; +import * as Shared from '../../shared'; +import * as ServicesAPI from './services'; +import { + Service, + ServiceCreateParams, + ServiceCreateResponse, + ServiceDeleteParams, + ServiceDeleteResponse, + ServiceListParams, + ServiceMetadata, + ServicePhase, + ServiceRetrieveParams, + ServiceRetrieveResponse, + ServiceSpec, + ServiceStartParams, + ServiceStartResponse, + ServiceStatus, + ServiceStopParams, + ServiceStopResponse, + ServiceUpdateParams, + ServiceUpdateResponse, + Services as ServicesAPIServices, + ServicesServicesPage, +} from './services'; +import * as TasksAPI from './tasks/tasks'; +import { + TaskCreateParams, + TaskCreateResponse, + TaskDeleteParams, + TaskDeleteResponse, + TaskListParams, + TaskRetrieveParams, + TaskRetrieveResponse, + TaskStartParams, + TaskStartResponse, + TaskUpdateParams, + TaskUpdateResponse, + Tasks as TasksAPITasks, +} from './tasks/tasks'; +import { APIPromise } from '../../../core/api-promise'; +import { RequestOptions } from '../../../internal/request-options'; + +export class Automations extends APIResource { + services: ServicesAPI.Services = new ServicesAPI.Services(this._client); + tasks: TasksAPI.Tasks = new TasksAPI.Tasks(this._client); + + /** + * Upserts the automations file for the given environment. + * + * Use this method to: + * + * - Configure environment automations + * - Update automation settings + * - Manage automation files + * + * ### Examples + * + * - Update automations file: + * + * Updates or creates the automations configuration. + * + * ```yaml + * environmentId: "07e03a28-65a5-4d98-b532-8ea67b188048" + * automationsFile: + * services: + * web-server: + * name: "Web Server" + * description: "Development web server" + * commands: + * start: "npm run dev" + * ready: "curl -s http://localhost:3000" + * triggeredBy: + * - postDevcontainerStart + * tasks: + * build: + * name: "Build Project" + * description: "Builds the project artifacts" + * command: "npm run build" + * triggeredBy: + * - postEnvironmentStart + * ``` + */ + upsert(body: AutomationUpsertParams, options?: RequestOptions): APIPromise<AutomationUpsertResponse> { + return this._client.post('/gitpod.v1.EnvironmentAutomationService/UpsertAutomationsFile', { + body, + ...options, + }); + } +} + +/** + * WARN: Do not remove any field here, as it will break reading automation yaml + * files. We error if there are any unknown fields in the yaml (to ensure the yaml + * is correct), but would break if we removed any fields. This includes marking a + * field as "reserved" in the proto file, this will also break reading the yaml. + */ +export interface AutomationsFile { + services?: Record<string, AutomationsFile.Services>; + + tasks?: Record<string, AutomationsFile.Tasks>; +} + +export namespace AutomationsFile { + export interface Services { + commands?: Services.Commands; + + description?: string; + + name?: string; + + runsOn?: Shared.RunsOn; + + triggeredBy?: Array<'manual' | 'postEnvironmentStart' | 'postDevcontainerStart'>; + } + + export namespace Services { + export interface Commands { + /** + * ready is an optional command that is run repeatedly until it exits with a zero + * exit code. If set, the service will first go into a Starting phase, and then + * into a Running phase once the ready command exits with a zero exit code. + */ + ready?: string; + + /** + * start is the command to start and run the service. If start exits, the service + * will transition to the following phase: + * + * - Stopped: if the exit code is 0 + * - Failed: if the exit code is not 0 If the stop command is not set, the start + * command will receive a SIGTERM signal when the service is requested to stop. + * If it does not exit within 2 minutes, it will receive a SIGKILL signal. + */ + start?: string; + + /** + * stop is an optional command that runs when the service is requested to stop. If + * set, instead of sending a SIGTERM signal to the start command, the stop command + * will be run. Once the stop command exits, the start command will receive a + * SIGKILL signal. If the stop command exits with a non-zero exit code, the service + * will transition to the Failed phase. If the stop command does not exit within 2 + * minutes, a SIGKILL signal will be sent to both the start and stop commands. + */ + stop?: string; + } + } + + export interface Tasks { + command?: string; + + dependsOn?: Array<string>; + + description?: string; + + name?: string; + + runsOn?: Shared.RunsOn; + + triggeredBy?: Array<'manual' | 'postEnvironmentStart' | 'postDevcontainerStart'>; + } +} + +export interface AutomationUpsertResponse { + updatedServiceIds?: Array<string>; + + updatedTaskIds?: Array<string>; +} + +export interface AutomationUpsertParams { + /** + * WARN: Do not remove any field here, as it will break reading automation yaml + * files. We error if there are any unknown fields in the yaml (to ensure the yaml + * is correct), but would break if we removed any fields. This includes marking a + * field as "reserved" in the proto file, this will also break reading the yaml. + */ + automationsFile?: AutomationsFile; + + environmentId?: string; +} + +Automations.Services = ServicesAPIServices; +Automations.Tasks = TasksAPITasks; + +export declare namespace Automations { + export { + type AutomationsFile as AutomationsFile, + type AutomationUpsertResponse as AutomationUpsertResponse, + type AutomationUpsertParams as AutomationUpsertParams, + }; + + export { + ServicesAPIServices as Services, + type Service as Service, + type ServiceMetadata as ServiceMetadata, + type ServicePhase as ServicePhase, + type ServiceSpec as ServiceSpec, + type ServiceStatus as ServiceStatus, + type ServiceCreateResponse as ServiceCreateResponse, + type ServiceRetrieveResponse as ServiceRetrieveResponse, + type ServiceUpdateResponse as ServiceUpdateResponse, + type ServiceDeleteResponse as ServiceDeleteResponse, + type ServiceStartResponse as ServiceStartResponse, + type ServiceStopResponse as ServiceStopResponse, + type ServicesServicesPage as ServicesServicesPage, + type ServiceCreateParams as ServiceCreateParams, + type ServiceRetrieveParams as ServiceRetrieveParams, + type ServiceUpdateParams as ServiceUpdateParams, + type ServiceListParams as ServiceListParams, + type ServiceDeleteParams as ServiceDeleteParams, + type ServiceStartParams as ServiceStartParams, + type ServiceStopParams as ServiceStopParams, + }; + + export { + TasksAPITasks as Tasks, + type TaskCreateResponse as TaskCreateResponse, + type TaskRetrieveResponse as TaskRetrieveResponse, + type TaskUpdateResponse as TaskUpdateResponse, + type TaskDeleteResponse as TaskDeleteResponse, + type TaskStartResponse as TaskStartResponse, + type TaskCreateParams as TaskCreateParams, + type TaskRetrieveParams as TaskRetrieveParams, + type TaskUpdateParams as TaskUpdateParams, + type TaskListParams as TaskListParams, + type TaskDeleteParams as TaskDeleteParams, + type TaskStartParams as TaskStartParams, + }; +} diff --git a/src/resources/environments/automations/index.ts b/src/resources/environments/automations/index.ts new file mode 100644 index 0000000..052267d --- /dev/null +++ b/src/resources/environments/automations/index.ts @@ -0,0 +1,44 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export { + Automations, + type AutomationsFile, + type AutomationUpsertResponse, + type AutomationUpsertParams, +} from './automations'; +export { + Services, + type Service, + type ServiceMetadata, + type ServicePhase, + type ServiceSpec, + type ServiceStatus, + type ServiceCreateResponse, + type ServiceRetrieveResponse, + type ServiceUpdateResponse, + type ServiceDeleteResponse, + type ServiceStartResponse, + type ServiceStopResponse, + type ServiceCreateParams, + type ServiceRetrieveParams, + type ServiceUpdateParams, + type ServiceListParams, + type ServiceDeleteParams, + type ServiceStartParams, + type ServiceStopParams, + type ServicesServicesPage, +} from './services'; +export { + Tasks, + type TaskCreateResponse, + type TaskRetrieveResponse, + type TaskUpdateResponse, + type TaskDeleteResponse, + type TaskStartResponse, + type TaskCreateParams, + type TaskRetrieveParams, + type TaskUpdateParams, + type TaskListParams, + type TaskDeleteParams, + type TaskStartParams, +} from './tasks/index'; diff --git a/src/resources/environments/automations/services.ts b/src/resources/environments/automations/services.ts new file mode 100644 index 0000000..efd2c80 --- /dev/null +++ b/src/resources/environments/automations/services.ts @@ -0,0 +1,614 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../../../core/resource'; +import * as ServicesAPI from './services'; +import * as Shared from '../../shared'; +import { APIPromise } from '../../../core/api-promise'; +import { PagePromise, ServicesPage, type ServicesPageParams } from '../../../core/pagination'; +import { RequestOptions } from '../../../internal/request-options'; + +export class Services extends APIResource { + /** + * Creates a new automation service for an environment. + * + * Use this method to: + * + * - Set up long-running services + * - Configure service triggers + * - Define service dependencies + * - Specify runtime environments + * + * ### Examples + * + * - Create basic service: + * + * Creates a simple service with start command. + * + * ```yaml + * environmentId: "07e03a28-65a5-4d98-b532-8ea67b188048" + * metadata: + * reference: "web-server" + * name: "Web Server" + * description: "Runs the development web server" + * triggeredBy: + * - postDevcontainerStart: true + * spec: + * commands: + * start: "npm run dev" + * ready: "curl -s http://localhost:3000" + * ``` + * + * - Create Docker-based service: + * + * Creates a service running in a specific container. + * + * ```yaml + * environmentId: "07e03a28-65a5-4d98-b532-8ea67b188048" + * metadata: + * reference: "redis" + * name: "Redis Server" + * description: "Redis cache service" + * spec: + * commands: + * start: "redis-server" + * runsOn: + * docker: + * image: "redis:7" + * ``` + */ + create(body: ServiceCreateParams, options?: RequestOptions): APIPromise<ServiceCreateResponse> { + return this._client.post('/gitpod.v1.EnvironmentAutomationService/CreateService', { body, ...options }); + } + + /** + * Gets details about a specific automation service. + * + * Use this method to: + * + * - Check service status + * - View service configuration + * - Monitor service health + * - Retrieve service metadata + * + * ### Examples + * + * - Get service details: + * + * Retrieves information about a specific service. + * + * ```yaml + * id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + * ``` + */ + retrieve(body: ServiceRetrieveParams, options?: RequestOptions): APIPromise<ServiceRetrieveResponse> { + return this._client.post('/gitpod.v1.EnvironmentAutomationService/GetService', { body, ...options }); + } + + /** + * Updates an automation service configuration. + * + * Use this method to: + * + * - Modify service commands + * - Update triggers + * - Change runtime settings + * - Adjust dependencies + * + * ### Examples + * + * - Update commands: + * + * Changes service start and ready commands. + * + * ```yaml + * id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + * spec: + * commands: + * start: "npm run start:dev" + * ready: "curl -s http://localhost:8080" + * ``` + * + * - Update triggers: + * + * Modifies when the service starts. + * + * ```yaml + * id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + * metadata: + * triggeredBy: + * trigger: + * - postDevcontainerStart: true + * - manual: true + * ``` + */ + update(body: ServiceUpdateParams, options?: RequestOptions): APIPromise<unknown> { + return this._client.post('/gitpod.v1.EnvironmentAutomationService/UpdateService', { body, ...options }); + } + + /** + * Lists automation services with optional filtering. + * + * Use this method to: + * + * - View all services in an environment + * - Filter services by reference + * - Monitor service status + * + * ### Examples + * + * - List environment services: + * + * Shows all services for an environment. + * + * ```yaml + * filter: + * environmentIds: ["07e03a28-65a5-4d98-b532-8ea67b188048"] + * pagination: + * pageSize: 20 + * ``` + * + * - Filter by reference: + * + * Lists services matching specific references. + * + * ```yaml + * filter: + * references: ["web-server", "database"] + * pagination: + * pageSize: 20 + * ``` + */ + list(params: ServiceListParams, options?: RequestOptions): PagePromise<ServicesServicesPage, Service> { + const { token, pageSize, ...body } = params; + return this._client.getAPIList( + '/gitpod.v1.EnvironmentAutomationService/ListServices', + ServicesPage<Service>, + { query: { token, pageSize }, body, method: 'post', ...options }, + ); + } + + /** + * Deletes an automation service. This call does not block until the service is + * deleted. If the service is not stopped it will be stopped before deletion. + * + * Use this method to: + * + * - Remove unused services + * - Clean up service configurations + * - Stop and delete services + * + * ### Examples + * + * - Delete service: + * + * Removes a service after stopping it. + * + * ```yaml + * id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + * force: false + * ``` + * + * - Force delete: + * + * Immediately removes a service. + * + * ```yaml + * id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + * force: true + * ``` + */ + delete(body: ServiceDeleteParams, options?: RequestOptions): APIPromise<unknown> { + return this._client.post('/gitpod.v1.EnvironmentAutomationService/DeleteService', { body, ...options }); + } + + /** + * Starts an automation service. This call does not block until the service is + * started. This call will not error if the service is already running or has been + * started. + * + * Use this method to: + * + * - Start stopped services + * - Resume service operations + * - Trigger service initialization + * + * ### Examples + * + * - Start service: + * + * Starts a previously stopped service. + * + * ```yaml + * id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + * ``` + */ + start(body: ServiceStartParams, options?: RequestOptions): APIPromise<unknown> { + return this._client.post('/gitpod.v1.EnvironmentAutomationService/StartService', { body, ...options }); + } + + /** + * Stops an automation service. This call does not block until the service is + * stopped. This call will not error if the service is already stopped or has been + * stopped. + * + * Use this method to: + * + * - Pause service operations + * - Gracefully stop services + * - Prepare for updates + * + * ### Examples + * + * - Stop service: + * + * Gracefully stops a running service. + * + * ```yaml + * id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + * ``` + */ + stop(body: ServiceStopParams, options?: RequestOptions): APIPromise<unknown> { + return this._client.post('/gitpod.v1.EnvironmentAutomationService/StopService', { body, ...options }); + } +} + +export type ServicesServicesPage = ServicesPage<Service>; + +export interface Service { + id: string; + + environmentId?: string; + + metadata?: ServiceMetadata; + + spec?: ServiceSpec; + + status?: ServiceStatus; +} + +export interface ServiceMetadata { + /** + * created_at is the time the service was created. + */ + createdAt?: string; + + /** + * creator describes the principal who created the service. + */ + creator?: Shared.Subject; + + /** + * description is a user-facing description for the service. It can be used to + * provide context and documentation for the service. + */ + description?: string; + + /** + * name is a user-facing name for the service. Unlike the reference, this field is + * not unique, and not referenced by the system. This is a short descriptive name + * for the service. + */ + name?: string; + + /** + * reference is a user-facing identifier for the service which must be unique on + * the environment. It is used to express dependencies between services, and to + * identify the service in user interactions (e.g. the CLI). + */ + reference?: string; + + /** + * triggered_by is a list of trigger that start the service. + */ + triggeredBy?: Array<Shared.AutomationTrigger>; +} + +export type ServicePhase = + | 'SERVICE_PHASE_UNSPECIFIED' + | 'SERVICE_PHASE_STARTING' + | 'SERVICE_PHASE_RUNNING' + | 'SERVICE_PHASE_STOPPING' + | 'SERVICE_PHASE_STOPPED' + | 'SERVICE_PHASE_FAILED' + | 'SERVICE_PHASE_DELETED'; + +export interface ServiceSpec { + /** + * commands contains the commands to start, stop and check the readiness of the + * service + */ + commands?: ServiceSpec.Commands; + + /** + * desired_phase is the phase the service should be in. Used to start or stop the + * service. + */ + desiredPhase?: ServicePhase; + + /** + * runs_on specifies the environment the service should run on. + */ + runsOn?: Shared.RunsOn; + + /** + * session should be changed to trigger a restart of the service. If a service + * exits it will not be restarted until the session is changed. + */ + session?: string; + + /** + * version of the spec. The value of this field has no semantic meaning (e.g. don't + * interpret it as as a timestamp), but it can be used to impose a partial order. + * If a.spec_version < b.spec_version then a was the spec before b. + */ + specVersion?: string; +} + +export namespace ServiceSpec { + /** + * commands contains the commands to start, stop and check the readiness of the + * service + */ + export interface Commands { + /** + * ready is an optional command that is run repeatedly until it exits with a zero + * exit code. If set, the service will first go into a Starting phase, and then + * into a Running phase once the ready command exits with a zero exit code. + */ + ready?: string; + + /** + * start is the command to start and run the service. If start exits, the service + * will transition to the following phase: + * + * - Stopped: if the exit code is 0 + * - Failed: if the exit code is not 0 If the stop command is not set, the start + * command will receive a SIGTERM signal when the service is requested to stop. + * If it does not exit within 2 minutes, it will receive a SIGKILL signal. + */ + start?: string; + + /** + * stop is an optional command that runs when the service is requested to stop. If + * set, instead of sending a SIGTERM signal to the start command, the stop command + * will be run. Once the stop command exits, the start command will receive a + * SIGKILL signal. If the stop command exits with a non-zero exit code, the service + * will transition to the Failed phase. If the stop command does not exit within 2 + * minutes, a SIGKILL signal will be sent to both the start and stop commands. + */ + stop?: string; + } +} + +export interface ServiceStatus { + /** + * failure_message summarises why the service failed to operate. If this is + * non-empty the service has failed to operate and will likely transition to a + * failed state. + */ + failureMessage?: string; + + /** + * log_url contains the URL at which the service logs can be accessed. + */ + logUrl?: string; + + /** + * output contains the output of the service. setting an output field to empty + * string will unset it. + */ + output?: Record<string, string>; + + /** + * phase is the current phase of the service. + */ + phase?: ServicePhase; + + /** + * session is the current session of the service. + */ + session?: string; + + /** + * version of the status update. Service instances themselves are unversioned, but + * their status has different versions. The value of this field has no semantic + * meaning (e.g. don't interpret it as as a timestamp), but it can be used to + * impose a partial order. If a.status_version < b.status_version then a was the + * status before b. + */ + statusVersion?: string; +} + +export interface ServiceCreateResponse { + service: Service; +} + +export interface ServiceRetrieveResponse { + service: Service; +} + +export type ServiceUpdateResponse = unknown; + +export type ServiceDeleteResponse = unknown; + +export type ServiceStartResponse = unknown; + +export type ServiceStopResponse = unknown; + +export interface ServiceCreateParams { + environmentId?: string; + + metadata?: ServiceMetadata; + + spec?: ServiceSpec; +} + +export interface ServiceRetrieveParams { + id?: string; +} + +export interface ServiceUpdateParams { + id?: string; + + metadata?: ServiceUpdateParams.Metadata; + + /** + * Changing the spec of a service is a complex operation. The spec of a service can + * only be updated if the service is in a stopped state. If the service is running, + * it must be stopped first. + */ + spec?: ServiceUpdateParams.Spec; + + /** + * Service status updates are only expected from the executing environment. As a + * client of this API you are not expected to provide this field. Updating this + * field requires the `environmentservice:update_status` permission. + */ + status?: ServiceUpdateParams.Status; +} + +export namespace ServiceUpdateParams { + export interface Metadata { + description?: string | null; + + name?: string | null; + + triggeredBy?: Metadata.TriggeredBy | null; + } + + export namespace Metadata { + export interface TriggeredBy { + trigger?: Array<Shared.AutomationTrigger>; + } + } + + /** + * Changing the spec of a service is a complex operation. The spec of a service can + * only be updated if the service is in a stopped state. If the service is running, + * it must be stopped first. + */ + export interface Spec { + commands?: Spec.Commands | null; + + runsOn?: Shared.RunsOn | null; + } + + export namespace Spec { + export interface Commands { + ready?: string | null; + + start?: string | null; + + stop?: string | null; + } + } + + /** + * Service status updates are only expected from the executing environment. As a + * client of this API you are not expected to provide this field. Updating this + * field requires the `environmentservice:update_status` permission. + */ + export interface Status { + failureMessage?: string | null; + + logUrl?: string | null; + + /** + * setting an output field to empty string will unset it. + */ + output?: Record<string, string>; + + phase?: ServicesAPI.ServicePhase | null; + + session?: string | null; + } +} + +export interface ServiceListParams extends ServicesPageParams { + /** + * Body param: filter contains the filter options for listing services + */ + filter?: ServiceListParams.Filter; + + /** + * Body param: pagination contains the pagination options for listing services + */ + pagination?: ServiceListParams.Pagination; +} + +export namespace ServiceListParams { + /** + * filter contains the filter options for listing services + */ + export interface Filter { + /** + * environment_ids filters the response to only services of these environments + */ + environmentIds?: Array<string>; + + /** + * references filters the response to only services with these references + */ + references?: Array<string>; + + /** + * service_ids filters the response to only services with these IDs + */ + serviceIds?: Array<string>; + } + + /** + * pagination contains the pagination options for listing services + */ + export interface Pagination { + /** + * Token for the next set of results that was returned as next_token of a + * PaginationResponse + */ + token?: string; + + /** + * Page size is the maximum number of results to retrieve per page. Defaults to 25. + * Maximum 100. + */ + pageSize?: number; + } +} + +export interface ServiceDeleteParams { + id?: string; + + force?: boolean; +} + +export interface ServiceStartParams { + id?: string; +} + +export interface ServiceStopParams { + id?: string; +} + +export declare namespace Services { + export { + type Service as Service, + type ServiceMetadata as ServiceMetadata, + type ServicePhase as ServicePhase, + type ServiceSpec as ServiceSpec, + type ServiceStatus as ServiceStatus, + type ServiceCreateResponse as ServiceCreateResponse, + type ServiceRetrieveResponse as ServiceRetrieveResponse, + type ServiceUpdateResponse as ServiceUpdateResponse, + type ServiceDeleteResponse as ServiceDeleteResponse, + type ServiceStartResponse as ServiceStartResponse, + type ServiceStopResponse as ServiceStopResponse, + type ServicesServicesPage as ServicesServicesPage, + type ServiceCreateParams as ServiceCreateParams, + type ServiceRetrieveParams as ServiceRetrieveParams, + type ServiceUpdateParams as ServiceUpdateParams, + type ServiceListParams as ServiceListParams, + type ServiceDeleteParams as ServiceDeleteParams, + type ServiceStartParams as ServiceStartParams, + type ServiceStopParams as ServiceStopParams, + }; +} diff --git a/src/resources/environments/automations/tasks.ts b/src/resources/environments/automations/tasks.ts new file mode 100644 index 0000000..a93e814 --- /dev/null +++ b/src/resources/environments/automations/tasks.ts @@ -0,0 +1,3 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export * from './tasks/index'; diff --git a/src/resources/environments/automations/tasks/executions.ts b/src/resources/environments/automations/tasks/executions.ts new file mode 100644 index 0000000..47410d8 --- /dev/null +++ b/src/resources/environments/automations/tasks/executions.ts @@ -0,0 +1,190 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../../../../core/resource'; +import * as Shared from '../../../shared'; +import { TaskExecutionsTaskExecutionsPage } from '../../../shared'; +import { APIPromise } from '../../../../core/api-promise'; +import { PagePromise, TaskExecutionsPage, type TaskExecutionsPageParams } from '../../../../core/pagination'; +import { RequestOptions } from '../../../../internal/request-options'; + +export class Executions extends APIResource { + /** + * Gets details about a specific task execution. + * + * Use this method to: + * + * - Monitor execution progress + * - View execution logs + * - Check execution status + * - Debug failed executions + * + * ### Examples + * + * - Get execution details: + * + * Retrieves information about a specific task execution. + * + * ```yaml + * id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + * ``` + */ + retrieve(body: ExecutionRetrieveParams, options?: RequestOptions): APIPromise<ExecutionRetrieveResponse> { + return this._client.post('/gitpod.v1.EnvironmentAutomationService/GetTaskExecution', { + body, + ...options, + }); + } + + /** + * Lists executions of automation tasks. + * + * Use this method to: + * + * - View task execution history + * - Monitor running tasks + * - Track task completion status + * + * ### Examples + * + * - List all executions: + * + * Shows execution history for all tasks. + * + * ```yaml + * filter: + * environmentIds: ["07e03a28-65a5-4d98-b532-8ea67b188048"] + * pagination: + * pageSize: 20 + * ``` + * + * - Filter by phase: + * + * Lists executions in specific phases. + * + * ```yaml + * filter: + * phases: ["TASK_EXECUTION_PHASE_RUNNING", "TASK_EXECUTION_PHASE_FAILED"] + * pagination: + * pageSize: 20 + * ``` + */ + list( + params: ExecutionListParams, + options?: RequestOptions, + ): PagePromise<TaskExecutionsTaskExecutionsPage, Shared.TaskExecution> { + const { token, pageSize, ...body } = params; + return this._client.getAPIList( + '/gitpod.v1.EnvironmentAutomationService/ListTaskExecutions', + TaskExecutionsPage<Shared.TaskExecution>, + { query: { token, pageSize }, body, method: 'post', ...options }, + ); + } + + /** + * Stops a running task execution. + * + * Use this method to: + * + * - Cancel long-running tasks + * - Stop failed executions + * - Interrupt task processing + * + * ### Examples + * + * - Stop execution: + * + * Stops a running task execution. + * + * ```yaml + * id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + * ``` + */ + stop(body: ExecutionStopParams, options?: RequestOptions): APIPromise<unknown> { + return this._client.post('/gitpod.v1.EnvironmentAutomationService/StopTaskExecution', { + body, + ...options, + }); + } +} + +export interface ExecutionRetrieveResponse { + taskExecution: Shared.TaskExecution; +} + +export type ExecutionStopResponse = unknown; + +export interface ExecutionRetrieveParams { + id?: string; +} + +export interface ExecutionListParams extends TaskExecutionsPageParams { + /** + * Body param: filter contains the filter options for listing task runs + */ + filter?: ExecutionListParams.Filter; + + /** + * Body param: pagination contains the pagination options for listing task runs + */ + pagination?: ExecutionListParams.Pagination; +} + +export namespace ExecutionListParams { + /** + * filter contains the filter options for listing task runs + */ + export interface Filter { + /** + * environment_ids filters the response to only task runs of these environments + */ + environmentIds?: Array<string>; + + /** + * phases filters the response to only task runs in these phases + */ + phases?: Array<Shared.TaskExecutionPhase>; + + /** + * task_ids filters the response to only task runs of these tasks + */ + taskIds?: Array<string>; + + /** + * task_references filters the response to only task runs with this reference + */ + taskReferences?: Array<string>; + } + + /** + * pagination contains the pagination options for listing task runs + */ + export interface Pagination { + /** + * Token for the next set of results that was returned as next_token of a + * PaginationResponse + */ + token?: string; + + /** + * Page size is the maximum number of results to retrieve per page. Defaults to 25. + * Maximum 100. + */ + pageSize?: number; + } +} + +export interface ExecutionStopParams { + id?: string; +} + +export declare namespace Executions { + export { + type ExecutionRetrieveResponse as ExecutionRetrieveResponse, + type ExecutionStopResponse as ExecutionStopResponse, + type ExecutionRetrieveParams as ExecutionRetrieveParams, + type ExecutionListParams as ExecutionListParams, + type ExecutionStopParams as ExecutionStopParams, + }; +} + +export { type TaskExecutionsTaskExecutionsPage }; diff --git a/src/resources/environments/automations/tasks/index.ts b/src/resources/environments/automations/tasks/index.ts new file mode 100644 index 0000000..1c21f28 --- /dev/null +++ b/src/resources/environments/automations/tasks/index.ts @@ -0,0 +1,24 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export { + Executions, + type ExecutionRetrieveResponse, + type ExecutionStopResponse, + type ExecutionRetrieveParams, + type ExecutionListParams, + type ExecutionStopParams, +} from './executions'; +export { + Tasks, + type TaskCreateResponse, + type TaskRetrieveResponse, + type TaskUpdateResponse, + type TaskDeleteResponse, + type TaskStartResponse, + type TaskCreateParams, + type TaskRetrieveParams, + type TaskUpdateParams, + type TaskListParams, + type TaskDeleteParams, + type TaskStartParams, +} from './tasks'; diff --git a/src/resources/environments/automations/tasks/tasks.ts b/src/resources/environments/automations/tasks/tasks.ts new file mode 100644 index 0000000..6a85c1f --- /dev/null +++ b/src/resources/environments/automations/tasks/tasks.ts @@ -0,0 +1,371 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../../../../core/resource'; +import * as Shared from '../../../shared'; +import { TasksTasksPage } from '../../../shared'; +import * as ExecutionsAPI from './executions'; +import { + ExecutionListParams, + ExecutionRetrieveParams, + ExecutionRetrieveResponse, + ExecutionStopParams, + ExecutionStopResponse, + Executions, +} from './executions'; +import { APIPromise } from '../../../../core/api-promise'; +import { PagePromise, TasksPage, type TasksPageParams } from '../../../../core/pagination'; +import { RequestOptions } from '../../../../internal/request-options'; + +export class Tasks extends APIResource { + executions: ExecutionsAPI.Executions = new ExecutionsAPI.Executions(this._client); + + /** + * Creates a new automation task. + * + * Use this method to: + * + * - Define one-off or scheduled tasks + * - Set up build or test automation + * - Configure task dependencies + * - Specify execution environments + * + * ### Examples + * + * - Create basic task: + * + * Creates a simple build task. + * + * ```yaml + * environmentId: "07e03a28-65a5-4d98-b532-8ea67b188048" + * metadata: + * reference: "build" + * name: "Build Project" + * description: "Builds the project artifacts" + * triggeredBy: + * - postEnvironmentStart: true + * spec: + * command: "npm run build" + * ``` + * + * - Create task with dependencies: + * + * Creates a task that depends on other services. + * + * ```yaml + * environmentId: "07e03a28-65a5-4d98-b532-8ea67b188048" + * metadata: + * reference: "test" + * name: "Run Tests" + * description: "Runs the test suite" + * spec: + * command: "npm test" + * dependsOn: ["d2c94c27-3b76-4a42-b88c-95a85e392c68"] + * ``` + */ + create(body: TaskCreateParams, options?: RequestOptions): APIPromise<TaskCreateResponse> { + return this._client.post('/gitpod.v1.EnvironmentAutomationService/CreateTask', { body, ...options }); + } + + /** + * Gets details about a specific automation task. + * + * Use this method to: + * + * - Check task configuration + * - View task dependencies + * - Monitor task status + * + * ### Examples + * + * - Get task details: + * + * Retrieves information about a specific task. + * + * ```yaml + * id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + * ``` + */ + retrieve(body: TaskRetrieveParams, options?: RequestOptions): APIPromise<TaskRetrieveResponse> { + return this._client.post('/gitpod.v1.EnvironmentAutomationService/GetTask', { body, ...options }); + } + + /** + * Updates an automation task configuration. + * + * Use this method to: + * + * - Modify task commands + * - Update task triggers + * - Change dependencies + * - Adjust execution settings + * + * ### Examples + * + * - Update command: + * + * Changes the task's command. + * + * ```yaml + * id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + * spec: + * command: "npm run test:coverage" + * ``` + * + * - Update triggers: + * + * Modifies when the task runs. + * + * ```yaml + * id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + * metadata: + * triggeredBy: + * trigger: + * - postEnvironmentStart: true + * ``` + */ + update(body: TaskUpdateParams, options?: RequestOptions): APIPromise<unknown> { + return this._client.post('/gitpod.v1.EnvironmentAutomationService/UpdateTask', { body, ...options }); + } + + /** + * Lists automation tasks with optional filtering. + * + * Use this method to: + * + * - View all tasks in an environment + * - Filter tasks by reference + * - Monitor task status + * + * ### Examples + * + * - List environment tasks: + * + * Shows all tasks for an environment. + * + * ```yaml + * filter: + * environmentIds: ["07e03a28-65a5-4d98-b532-8ea67b188048"] + * pagination: + * pageSize: 20 + * ``` + * + * - Filter by reference: + * + * Lists tasks matching specific references. + * + * ```yaml + * filter: + * references: ["build", "test"] + * pagination: + * pageSize: 20 + * ``` + */ + list(params: TaskListParams, options?: RequestOptions): PagePromise<TasksTasksPage, Shared.Task> { + const { token, pageSize, ...body } = params; + return this._client.getAPIList( + '/gitpod.v1.EnvironmentAutomationService/ListTasks', + TasksPage<Shared.Task>, + { query: { token, pageSize }, body, method: 'post', ...options }, + ); + } + + /** + * Deletes an automation task. + * + * Use this method to: + * + * - Remove unused tasks + * - Clean up task configurations + * - Delete obsolete automations + * + * ### Examples + * + * - Delete task: + * + * Removes a task and its configuration. + * + * ```yaml + * id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + * ``` + */ + delete(body: TaskDeleteParams, options?: RequestOptions): APIPromise<unknown> { + return this._client.post('/gitpod.v1.EnvironmentAutomationService/DeleteTask', { body, ...options }); + } + + /** + * Starts a task by creating a new task execution. This call does not block until + * the task is started; the task will be started asynchronously. + * + * Use this method to: + * + * - Trigger task execution + * - Run one-off tasks + * - Start scheduled tasks immediately + * + * ### Examples + * + * - Start task: + * + * Creates a new execution of a task. + * + * ```yaml + * id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + * ``` + */ + start(body: TaskStartParams, options?: RequestOptions): APIPromise<TaskStartResponse> { + return this._client.post('/gitpod.v1.EnvironmentAutomationService/StartTask', { body, ...options }); + } +} + +export interface TaskCreateResponse { + task: Shared.Task; +} + +export interface TaskRetrieveResponse { + task: Shared.Task; +} + +export type TaskUpdateResponse = unknown; + +export type TaskDeleteResponse = unknown; + +export interface TaskStartResponse { + taskExecution: Shared.TaskExecution; +} + +export interface TaskCreateParams { + dependsOn?: Array<string>; + + environmentId?: string; + + metadata?: Shared.TaskMetadata; + + spec?: Shared.TaskSpec; +} + +export interface TaskRetrieveParams { + id?: string; +} + +export interface TaskUpdateParams { + id?: string; + + /** + * dependencies specifies the IDs of the automations this task depends on. + */ + dependsOn?: Array<string>; + + metadata?: TaskUpdateParams.Metadata; + + spec?: TaskUpdateParams.Spec; +} + +export namespace TaskUpdateParams { + export interface Metadata { + description?: string | null; + + name?: string | null; + + triggeredBy?: Metadata.TriggeredBy | null; + } + + export namespace Metadata { + export interface TriggeredBy { + trigger?: Array<Shared.AutomationTrigger>; + } + } + + export interface Spec { + command?: string | null; + + runsOn?: Shared.RunsOn | null; + } +} + +export interface TaskListParams extends TasksPageParams { + /** + * Body param: filter contains the filter options for listing tasks + */ + filter?: TaskListParams.Filter; + + /** + * Body param: pagination contains the pagination options for listing tasks + */ + pagination?: TaskListParams.Pagination; +} + +export namespace TaskListParams { + /** + * filter contains the filter options for listing tasks + */ + export interface Filter { + /** + * environment_ids filters the response to only tasks of these environments + */ + environmentIds?: Array<string>; + + /** + * references filters the response to only services with these references + */ + references?: Array<string>; + + /** + * task_ids filters the response to only tasks with these IDs + */ + taskIds?: Array<string>; + } + + /** + * pagination contains the pagination options for listing tasks + */ + export interface Pagination { + /** + * Token for the next set of results that was returned as next_token of a + * PaginationResponse + */ + token?: string; + + /** + * Page size is the maximum number of results to retrieve per page. Defaults to 25. + * Maximum 100. + */ + pageSize?: number; + } +} + +export interface TaskDeleteParams { + id?: string; +} + +export interface TaskStartParams { + id?: string; +} + +Tasks.Executions = Executions; + +export declare namespace Tasks { + export { + type TaskCreateResponse as TaskCreateResponse, + type TaskRetrieveResponse as TaskRetrieveResponse, + type TaskUpdateResponse as TaskUpdateResponse, + type TaskDeleteResponse as TaskDeleteResponse, + type TaskStartResponse as TaskStartResponse, + type TaskCreateParams as TaskCreateParams, + type TaskRetrieveParams as TaskRetrieveParams, + type TaskUpdateParams as TaskUpdateParams, + type TaskListParams as TaskListParams, + type TaskDeleteParams as TaskDeleteParams, + type TaskStartParams as TaskStartParams, + }; + + export { + Executions as Executions, + type ExecutionRetrieveResponse as ExecutionRetrieveResponse, + type ExecutionStopResponse as ExecutionStopResponse, + type ExecutionRetrieveParams as ExecutionRetrieveParams, + type ExecutionListParams as ExecutionListParams, + type ExecutionStopParams as ExecutionStopParams, + }; +} + +export { type TasksTasksPage }; diff --git a/src/resources/environments/classes.ts b/src/resources/environments/classes.ts new file mode 100644 index 0000000..709e8bc --- /dev/null +++ b/src/resources/environments/classes.ts @@ -0,0 +1,117 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../../core/resource'; +import * as Shared from '../shared'; +import { EnvironmentClassesEnvironmentClassesPage } from '../shared'; +import * as RunnersAPI from '../runners/runners'; +import { + EnvironmentClassesPage, + type EnvironmentClassesPageParams, + PagePromise, +} from '../../core/pagination'; +import { RequestOptions } from '../../internal/request-options'; + +export class Classes extends APIResource { + /** + * Lists available environment classes with their specifications and resource + * limits. + * + * Use this method to understand what types of environments you can create and + * their capabilities. Environment classes define the compute resources and + * features available to your environments. + * + * ### Examples + * + * - List all available classes: + * + * Retrieves a list of all environment classes with their specifications. + * + * ```yaml + * {} + * ``` + * + * buf:lint:ignore RPC_REQUEST_RESPONSE_UNIQUE + */ + list( + params: ClassListParams, + options?: RequestOptions, + ): PagePromise<EnvironmentClassesEnvironmentClassesPage, Shared.EnvironmentClass> { + const { token, pageSize, ...body } = params; + return this._client.getAPIList( + '/gitpod.v1.EnvironmentService/ListEnvironmentClasses', + EnvironmentClassesPage<Shared.EnvironmentClass>, + { query: { token, pageSize }, body, method: 'post', ...options }, + ); + } +} + +export interface ClassListParams extends EnvironmentClassesPageParams { + /** + * Body param: + */ + filter?: ClassListParams.Filter; + + /** + * Body param: pagination contains the pagination options for listing environment + * classes + */ + pagination?: ClassListParams.Pagination; +} + +export namespace ClassListParams { + export interface Filter { + /** + * can_create_environments filters the response to only environment classes that + * can be used to create new environments by the caller. Unlike enabled, which + * indicates general availability, this ensures the caller only sees environment + * classes they are allowed to use. + */ + canCreateEnvironments?: boolean | null; + + /** + * enabled filters the response to only enabled or disabled environment classes. If + * not set, all environment classes are returned. + */ + enabled?: boolean | null; + + /** + * runner_ids filters the response to only EnvironmentClasses of these Runner IDs + */ + runnerIds?: Array<string>; + + /** + * runner_kind filters the response to only environment classes from runners of + * these kinds. + */ + runnerKinds?: Array<RunnersAPI.RunnerKind>; + + /** + * runner_providers filters the response to only environment classes from runners + * of these providers. + */ + runnerProviders?: Array<RunnersAPI.RunnerProvider>; + } + + /** + * pagination contains the pagination options for listing environment classes + */ + export interface Pagination { + /** + * Token for the next set of results that was returned as next_token of a + * PaginationResponse + */ + token?: string; + + /** + * Page size is the maximum number of results to retrieve per page. Defaults to 25. + * Maximum 100. + */ + pageSize?: number; + } +} + +export declare namespace Classes { + export { type ClassListParams as ClassListParams }; +} + +export { type EnvironmentClassesEnvironmentClassesPage }; diff --git a/src/resources/environments/environments.ts b/src/resources/environments/environments.ts new file mode 100644 index 0000000..695ee9e --- /dev/null +++ b/src/resources/environments/environments.ts @@ -0,0 +1,1641 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../../core/resource'; +import * as EnvironmentsAPI from './environments'; +import * as Shared from '../shared'; +import * as ClassesAPI from './classes'; +import { ClassListParams, Classes } from './classes'; +import * as ProjectsAPI from '../projects/projects'; +import * as RunnersAPI from '../runners/runners'; +import * as AutomationsAPI from './automations/automations'; +import { + AutomationUpsertParams, + AutomationUpsertResponse, + Automations, + AutomationsFile as AutomationsAPIAutomationsFile, +} from './automations/automations'; +import { APIPromise } from '../../core/api-promise'; +import { EnvironmentsPage, type EnvironmentsPageParams, PagePromise } from '../../core/pagination'; +import { RequestOptions } from '../../internal/request-options'; + +export class Environments extends APIResource { + automations: AutomationsAPI.Automations = new AutomationsAPI.Automations(this._client); + classes: ClassesAPI.Classes = new ClassesAPI.Classes(this._client); + + /** + * Creates a development environment from a context URL (e.g. Git repository) and + * starts it. + * + * The `class` field must be a valid environment class ID. You can find a list of + * available environment classes with the `ListEnvironmentClasses` method. + * + * ### Examples + * + * - Create from context URL: + * + * Creates an environment from a Git repository URL with default settings. + * + * ```yaml + * spec: + * machine: + * class: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + * content: + * initializer: + * specs: + * - contextUrl: + * url: "https://github.com/gitpod-io/gitpod" + * ``` + * + * - Create from Git repository: + * + * Creates an environment from a Git repository with specific branch targeting. + * + * ```yaml + * spec: + * machine: + * class: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + * content: + * initializer: + * specs: + * - git: + * remoteUri: "https://github.com/gitpod-io/gitpod" + * cloneTarget: "main" + * targetMode: "CLONE_TARGET_MODE_REMOTE_BRANCH" + * ``` + * + * - Create with custom timeout and ports: + * + * Creates an environment with custom inactivity timeout and exposed port + * configuration. + * + * ```yaml + * spec: + * machine: + * class: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + * content: + * initializer: + * specs: + * - contextUrl: + * url: "https://github.com/gitpod-io/gitpod" + * timeout: + * disconnected: "7200s" # 2 hours in seconds + * ports: + * - port: 3000 + * admission: "ADMISSION_LEVEL_EVERYONE" + * name: "Web App" + * ``` + */ + create(body: EnvironmentCreateParams, options?: RequestOptions): APIPromise<EnvironmentCreateResponse> { + return this._client.post('/gitpod.v1.EnvironmentService/CreateEnvironment', { body, ...options }); + } + + /** + * Gets details about a specific environment including its status, configuration, + * and context URL. + * + * Use this method to: + * + * - Check if an environment is ready to use + * - Get connection details for IDE and exposed ports + * - Monitor environment health and resource usage + * - Debug environment setup issues + * + * ### Examples + * + * - Get environment details: + * + * Retrieves detailed information about a specific environment using its unique + * identifier. + * + * ```yaml + * environmentId: "07e03a28-65a5-4d98-b532-8ea67b188048" + * ``` + */ + retrieve( + body: EnvironmentRetrieveParams, + options?: RequestOptions, + ): APIPromise<EnvironmentRetrieveResponse> { + return this._client.post('/gitpod.v1.EnvironmentService/GetEnvironment', { body, ...options }); + } + + /** + * Updates an environment's configuration while it is running. + * + * Updates are limited to: + * + * - Git credentials (username, email) + * - SSH public keys + * - Content initialization + * - Port configurations + * - Automation files + * - Environment timeouts + * + * ### Examples + * + * - Update Git credentials: + * + * Updates the Git configuration for the environment. + * + * ```yaml + * environmentId: "07e03a28-65a5-4d98-b532-8ea67b188048" + * spec: + * content: + * gitUsername: "example-user" + * gitEmail: "user@example.com" + * ``` + * + * - Add SSH public key: + * + * Adds a new SSH public key for authentication. + * + * ```yaml + * environmentId: "07e03a28-65a5-4d98-b532-8ea67b188048" + * spec: + * sshPublicKeys: + * - id: "0194b7c1-c954-718d-91a4-9a742aa5fc11" + * value: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI..." + * ``` + * + * - Update content session: + * + * Updates the content session identifier for the environment. + * + * ```yaml + * environmentId: "07e03a28-65a5-4d98-b532-8ea67b188048" + * spec: + * content: + * session: "0194b7c1-c954-718d-91a4-9a742aa5fc11" + * ``` + * + * Note: Machine class changes require stopping the environment and creating a new + * one. + */ + update(body: EnvironmentUpdateParams, options?: RequestOptions): APIPromise<unknown> { + return this._client.post('/gitpod.v1.EnvironmentService/UpdateEnvironment', { body, ...options }); + } + + /** + * Lists all environments matching the specified criteria. + * + * Use this method to find and monitor environments across your organization. + * Results are ordered by creation time with newest environments first. + * + * ### Examples + * + * - List running environments for a project: + * + * Retrieves all running environments for a specific project with pagination. + * + * ```yaml + * filter: + * statusPhases: ["ENVIRONMENT_PHASE_RUNNING"] + * projectIds: ["b0e12f6c-4c67-429d-a4a6-d9838b5da047"] + * pagination: + * pageSize: 10 + * ``` + * + * - List all environments for a specific runner: + * + * Filters environments by runner ID and creator ID. + * + * ```yaml + * filter: + * runnerIds: ["e6aa9c54-89d3-42c1-ac31-bd8d8f1concentrate"] + * creatorIds: ["f53d2330-3795-4c5d-a1f3-453121af9c60"] + * ``` + * + * - List stopped and deleted environments: + * + * Retrieves all environments in stopped or deleted state. + * + * ```yaml + * filter: + * statusPhases: ["ENVIRONMENT_PHASE_STOPPED", "ENVIRONMENT_PHASE_DELETED"] + * ``` + */ + list( + params: EnvironmentListParams, + options?: RequestOptions, + ): PagePromise<EnvironmentsEnvironmentsPage, Environment> { + const { token, pageSize, ...body } = params; + return this._client.getAPIList( + '/gitpod.v1.EnvironmentService/ListEnvironments', + EnvironmentsPage<Environment>, + { query: { token, pageSize }, body, method: 'post', ...options }, + ); + } + + /** + * Permanently deletes an environment. + * + * Running environments are automatically stopped before deletion. If force is + * true, the environment is deleted immediately without graceful shutdown. + * + * ### Examples + * + * - Delete with graceful shutdown: + * + * Deletes an environment after gracefully stopping it. + * + * ```yaml + * environmentId: "07e03a28-65a5-4d98-b532-8ea67b188048" + * force: false + * ``` + * + * - Force delete: + * + * Immediately deletes an environment without waiting for graceful shutdown. + * + * ```yaml + * environmentId: "07e03a28-65a5-4d98-b532-8ea67b188048" + * force: true + * ``` + */ + delete(body: EnvironmentDeleteParams, options?: RequestOptions): APIPromise<unknown> { + return this._client.post('/gitpod.v1.EnvironmentService/DeleteEnvironment', { body, ...options }); + } + + /** + * Creates an access token for the environment. + * + * Generated tokens are valid for one hour and provide environment-specific access + * permissions. The token is scoped to a specific environment. + * + * ### Examples + * + * - Generate environment token: + * + * Creates a temporary access token for accessing an environment. + * + * ```yaml + * environmentId: "07e03a28-65a5-4d98-b532-8ea67b188048" + * ``` + */ + createEnvironmentToken( + body: EnvironmentCreateEnvironmentTokenParams, + options?: RequestOptions, + ): APIPromise<EnvironmentCreateEnvironmentTokenResponse> { + return this._client.post('/gitpod.v1.EnvironmentService/CreateEnvironmentAccessToken', { + body, + ...options, + }); + } + + /** + * Creates an environment from an existing project configuration and starts it. + * + * This method uses project settings as defaults but allows overriding specific + * configurations. Project settings take precedence over default configurations, + * while custom specifications in the request override project settings. + * + * ### Examples + * + * - Create with project defaults: + * + * Creates an environment using all default settings from the project + * configuration. + * + * ```yaml + * projectId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + * ``` + * + * - Create with custom compute resources: + * + * Creates an environment from project with custom machine class and timeout + * settings. + * + * ```yaml + * projectId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + * spec: + * machine: + * class: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + * timeout: + * disconnected: "14400s" # 4 hours in seconds + * ``` + */ + createFromProject( + body: EnvironmentCreateFromProjectParams, + options?: RequestOptions, + ): APIPromise<EnvironmentCreateFromProjectResponse> { + return this._client.post('/gitpod.v1.EnvironmentService/CreateEnvironmentFromProject', { + body, + ...options, + }); + } + + /** + * Creates an access token for retrieving environment logs. + * + * Generated tokens are valid for one hour and provide read-only access to the + * environment's logs. + * + * ### Examples + * + * - Generate logs token: + * + * Creates a temporary access token for retrieving environment logs. + * + * ```yaml + * environmentId: "07e03a28-65a5-4d98-b532-8ea67b188048" + * ``` + */ + createLogsToken( + body: EnvironmentCreateLogsTokenParams, + options?: RequestOptions, + ): APIPromise<EnvironmentCreateLogsTokenResponse> { + return this._client.post('/gitpod.v1.EnvironmentService/CreateEnvironmentLogsToken', { + body, + ...options, + }); + } + + /** + * Records environment activity to prevent automatic shutdown. + * + * Activity signals should be sent every 5 minutes while the environment is + * actively being used. The source must be between 3-80 characters. + * + * ### Examples + * + * - Signal VS Code activity: + * + * Records VS Code editor activity to prevent environment shutdown. + * + * ```yaml + * environmentId: "07e03a28-65a5-4d98-b532-8ea67b188048" + * activitySignal: + * source: "VS Code" + * timestamp: "2025-02-12T14:30:00Z" + * ``` + */ + markActive(body: EnvironmentMarkActiveParams, options?: RequestOptions): APIPromise<unknown> { + return this._client.post('/gitpod.v1.EnvironmentService/MarkEnvironmentActive', { body, ...options }); + } + + /** + * Starts a stopped environment. + * + * Use this method to resume work on a previously stopped environment. The + * environment retains its configuration and workspace content from when it was + * stopped. + * + * ### Examples + * + * - Start an environment: + * + * Resumes a previously stopped environment with its existing configuration. + * + * ```yaml + * environmentId: "07e03a28-65a5-4d98-b532-8ea67b188048" + * ``` + */ + start(body: EnvironmentStartParams, options?: RequestOptions): APIPromise<unknown> { + return this._client.post('/gitpod.v1.EnvironmentService/StartEnvironment', { body, ...options }); + } + + /** + * Stops a running environment. + * + * Use this method to pause work while preserving the environment's state. The + * environment can be resumed later using StartEnvironment. + * + * ### Examples + * + * - Stop an environment: + * + * Gracefully stops a running environment while preserving its state. + * + * ```yaml + * environmentId: "07e03a28-65a5-4d98-b532-8ea67b188048" + * ``` + */ + stop(body: EnvironmentStopParams, options?: RequestOptions): APIPromise<unknown> { + return this._client.post('/gitpod.v1.EnvironmentService/StopEnvironment', { body, ...options }); + } +} + +export type EnvironmentsEnvironmentsPage = EnvironmentsPage<Environment>; + +/** + * Admission level describes who can access an environment instance and its ports. + */ +export type AdmissionLevel = + | 'ADMISSION_LEVEL_UNSPECIFIED' + | 'ADMISSION_LEVEL_OWNER_ONLY' + | 'ADMISSION_LEVEL_EVERYONE'; + +/** + * +resource get environment + */ +export interface Environment { + /** + * ID is a unique identifier of this environment. No other environment with the + * same name must be managed by this environment manager + */ + id: string; + + /** + * Metadata is data associated with this environment that's required for other + * parts of Gitpod to function + */ + metadata?: EnvironmentMetadata; + + /** + * Spec is the configuration of the environment that's required for the runner to + * start the environment + */ + spec?: EnvironmentSpec; + + /** + * Status is the current status of the environment + */ + status?: EnvironmentStatus; +} + +/** + * EnvironmentActivitySignal used to signal activity for an environment. + */ +export interface EnvironmentActivitySignal { + /** + * source of the activity signal, such as "VS Code", "SSH", or "Automations". It + * should be a human-readable string that describes the source of the activity + * signal. + */ + source?: string; + + /** + * timestamp of when the activity was observed by the source. Only reported every 5 + * minutes. Zero value means no activity was observed. + */ + timestamp?: string; +} + +/** + * EnvironmentMetadata is data associated with an environment that's required for + * other parts of the system to function + */ +export interface EnvironmentMetadata { + /** + * annotations are key/value pairs that gets attached to the environment. + * +internal - not yet implemented + */ + annotations?: Record<string, string>; + + /** + * Time when the Environment was created. + */ + createdAt?: string; + + /** + * creator is the identity of the creator of the environment + */ + creator?: Shared.Subject; + + /** + * Time when the Environment was last started (i.e. CreateEnvironment or + * StartEnvironment were called). + */ + lastStartedAt?: string; + + /** + * name is the name of the environment as specified by the user + */ + name?: string; + + /** + * organization_id is the ID of the organization that contains the environment + */ + organizationId?: string; + + /** + * original_context_url is the normalized URL from which the environment was + * created + */ + originalContextUrl?: string; + + /** + * If the Environment was started from a project, the project_id will reference the + * project. + */ + projectId?: string; + + /** + * Runner is the ID of the runner that runs this environment. + */ + runnerId?: string; +} + +export type EnvironmentPhase = + | 'ENVIRONMENT_PHASE_UNSPECIFIED' + | 'ENVIRONMENT_PHASE_CREATING' + | 'ENVIRONMENT_PHASE_STARTING' + | 'ENVIRONMENT_PHASE_RUNNING' + | 'ENVIRONMENT_PHASE_UPDATING' + | 'ENVIRONMENT_PHASE_STOPPING' + | 'ENVIRONMENT_PHASE_STOPPED' + | 'ENVIRONMENT_PHASE_DELETING' + | 'ENVIRONMENT_PHASE_DELETED'; + +/** + * EnvironmentSpec specifies the configuration of an environment for an environment + * start + */ +export interface EnvironmentSpec { + /** + * admission controlls who can access the environment and its ports. + */ + admission?: AdmissionLevel; + + /** + * automations_file is the automations file spec of the environment + */ + automationsFile?: EnvironmentSpec.AutomationsFile; + + /** + * content is the content spec of the environment + */ + content?: EnvironmentSpec.Content; + + /** + * Phase is the desired phase of the environment + */ + desiredPhase?: EnvironmentPhase; + + /** + * devcontainer is the devcontainer spec of the environment + */ + devcontainer?: EnvironmentSpec.Devcontainer; + + /** + * machine is the machine spec of the environment + */ + machine?: EnvironmentSpec.Machine; + + /** + * ports is the set of ports which ought to be exposed to the internet + */ + ports?: Array<EnvironmentSpec.Port>; + + /** + * secrets are confidential data that is mounted into the environment + */ + secrets?: Array<EnvironmentSpec.Secret>; + + /** + * version of the spec. The value of this field has no semantic meaning (e.g. don't + * interpret it as as a timestamp), but it can be used to impose a partial order. + * If a.spec_version < b.spec_version then a was the spec before b. + */ + specVersion?: string; + + /** + * ssh_public_keys are the public keys used to ssh into the environment + */ + sshPublicKeys?: Array<EnvironmentSpec.SSHPublicKey>; + + /** + * Timeout configures the environment timeout + */ + timeout?: EnvironmentSpec.Timeout; +} + +export namespace EnvironmentSpec { + /** + * automations_file is the automations file spec of the environment + */ + export interface AutomationsFile { + /** + * automations_file_path is the path to the automations file that is applied in the + * environment, relative to the repo root. path must not be absolute (start with a + * /): + * + * ``` + * this.matches('^$|^[^/].*') + * ``` + */ + automationsFilePath?: string; + + session?: string; + } + + /** + * content is the content spec of the environment + */ + export interface Content { + /** + * The Git email address + */ + gitEmail?: string; + + /** + * The Git username + */ + gitUsername?: string; + + /** + * initializer configures how the environment is to be initialized + */ + initializer?: ProjectsAPI.EnvironmentInitializer; + + session?: string; + } + + /** + * devcontainer is the devcontainer spec of the environment + */ + export interface Devcontainer { + /** + * default_devcontainer_image is the default image that is used to start the + * devcontainer if no devcontainer config file is found + */ + defaultDevcontainerImage?: string; + + /** + * devcontainer_file_path is the path to the devcontainer file relative to the repo + * root path must not be absolute (start with a /): + * + * ``` + * this.matches('^$|^[^/].*') + * ``` + */ + devcontainerFilePath?: string; + + /** + * Experimental: dotfiles is the dotfiles configuration of the devcontainer + */ + dotfiles?: Devcontainer.Dotfiles; + + session?: string; + } + + export namespace Devcontainer { + /** + * Experimental: dotfiles is the dotfiles configuration of the devcontainer + */ + export interface Dotfiles { + /** + * URL of a dotfiles Git repository (e.g. https://github.com/owner/repository) + */ + repository: string; + } + } + + /** + * machine is the machine spec of the environment + */ + export interface Machine { + /** + * Class denotes the class of the environment we ought to start + */ + class?: string; + + session?: string; + } + + export interface Port { + /** + * policy of this port + */ + admission?: EnvironmentsAPI.AdmissionLevel; + + /** + * name of this port + */ + name?: string; + + /** + * port number + */ + port?: number; + } + + export interface Secret { + /** + * id is the unique identifier of the secret. + */ + id?: string; + + /** + * container_registry_basic_auth_host is the hostname of the container registry + * that supports basic auth + */ + containerRegistryBasicAuthHost?: string; + + environmentVariable?: string; + + /** + * file_path is the path inside the devcontainer where the secret is mounted + */ + filePath?: string; + + gitCredentialHost?: string; + + /** + * name is the human readable description of the secret + */ + name?: string; + + /** + * session indicated the current session of the secret. When the session does not + * change, secrets are not reloaded in the environment. + */ + session?: string; + + /** + * source is the source of the secret, for now control-plane or runner + */ + source?: string; + + /** + * source_ref into the source, in case of control-plane this is uuid of the secret + */ + sourceRef?: string; + } + + export interface SSHPublicKey { + /** + * id is the unique identifier of the public key + */ + id?: string; + + /** + * value is the actual public key in the public key file format + */ + value?: string; + } + + /** + * Timeout configures the environment timeout + */ + export interface Timeout { + /** + * inacitivity is the maximum time of disconnection before the environment is + * stopped or paused. Minimum duration is 30 minutes. Set to 0 to disable. + */ + disconnected?: string; + } +} + +/** + * EnvironmentStatus describes an environment status + */ +export interface EnvironmentStatus { + /** + * activity_signal is the last activity signal for the environment. + */ + activitySignal?: EnvironmentActivitySignal; + + /** + * automations_file contains the status of the automations file. + */ + automationsFile?: EnvironmentStatus.AutomationsFile; + + /** + * content contains the status of the environment content. + */ + content?: EnvironmentStatus.Content; + + /** + * devcontainer contains the status of the devcontainer. + */ + devcontainer?: EnvironmentStatus.Devcontainer; + + /** + * environment_url contains the URL at which the environment can be accessed. This + * field is only set if the environment is running. + */ + environmentUrls?: EnvironmentStatus.EnvironmentURLs; + + /** + * failure_message summarises why the environment failed to operate. If this is + * non-empty the environment has failed to operate and will likely transition to a + * stopped state. + */ + failureMessage?: Array<string>; + + /** + * machine contains the status of the environment machine + */ + machine?: EnvironmentStatus.Machine; + + /** + * the phase of an environment is a simple, high-level summary of where the + * environment is in its lifecycle + */ + phase?: EnvironmentPhase; + + /** + * runner_ack contains the acknowledgement from the runner that is has received the + * environment spec. + */ + runnerAck?: EnvironmentStatus.RunnerAck; + + /** + * secrets contains the status of the environment secrets + */ + secrets?: Array<EnvironmentStatus.Secret>; + + /** + * ssh_public_keys contains the status of the environment ssh public keys + */ + sshPublicKeys?: Array<EnvironmentStatus.SSHPublicKey>; + + /** + * version of the status update. Environment instances themselves are unversioned, + * but their status has different versions. The value of this field has no semantic + * meaning (e.g. don't interpret it as as a timestamp), but it can be used to + * impose a partial order. If a.status_version < b.status_version then a was the + * status before b. + */ + statusVersion?: string; + + /** + * warning_message contains warnings, e.g. when the environment is present but not + * in the expected state. + */ + warningMessage?: Array<string>; +} + +export namespace EnvironmentStatus { + /** + * automations_file contains the status of the automations file. + */ + export interface AutomationsFile { + /** + * automations_file_path is the path to the automations file relative to the repo + * root. + */ + automationsFilePath?: string; + + /** + * automations_file_presence indicates how an automations file is present in the + * environment. + */ + automationsFilePresence?: + | 'PRESENCE_UNSPECIFIED' + | 'PRESENCE_ABSENT' + | 'PRESENCE_DISCOVERED' + | 'PRESENCE_SPECIFIED'; + + /** + * failure_message contains the reason the automations file failed to be applied. + * This is only set if the phase is FAILED. + */ + failureMessage?: string; + + /** + * phase is the current phase of the automations file. + */ + phase?: + | 'CONTENT_PHASE_UNSPECIFIED' + | 'CONTENT_PHASE_CREATING' + | 'CONTENT_PHASE_INITIALIZING' + | 'CONTENT_PHASE_READY' + | 'CONTENT_PHASE_UPDATING' + | 'CONTENT_PHASE_FAILED'; + + /** + * session is the automations file session that is currently applied in the + * environment. + */ + session?: string; + + /** + * warning_message contains warnings, e.g. when no triggers are defined in the + * automations file. + */ + warningMessage?: string; + } + + /** + * content contains the status of the environment content. + */ + export interface Content { + /** + * content_location_in_machine is the location of the content in the machine + */ + contentLocationInMachine?: string; + + /** + * failure_message contains the reason the content initialization failed. + */ + failureMessage?: string; + + /** + * git is the Git working copy status of the environment. Note: this is a + * best-effort field and more often than not will not be present. Its absence does + * not indicate the absence of a working copy. + */ + git?: Content.Git; + + /** + * phase is the current phase of the environment content + */ + phase?: + | 'CONTENT_PHASE_UNSPECIFIED' + | 'CONTENT_PHASE_CREATING' + | 'CONTENT_PHASE_INITIALIZING' + | 'CONTENT_PHASE_READY' + | 'CONTENT_PHASE_UPDATING' + | 'CONTENT_PHASE_FAILED'; + + /** + * session is the session that is currently active in the environment. + */ + session?: string; + + /** + * warning_message contains warnings, e.g. when the content is present but not in + * the expected state. + */ + warningMessage?: string; + } + + export namespace Content { + /** + * git is the Git working copy status of the environment. Note: this is a + * best-effort field and more often than not will not be present. Its absence does + * not indicate the absence of a working copy. + */ + export interface Git { + /** + * branch is branch we're currently on + */ + branch?: string; + + /** + * changed_files is an array of changed files in the environment, possibly + * truncated + */ + changedFiles?: Array<Git.ChangedFile>; + + /** + * clone_url is the repository url as you would pass it to "git clone". Only HTTPS + * clone URLs are supported. + */ + cloneUrl?: string; + + /** + * latest_commit is the most recent commit on the current branch + */ + latestCommit?: string; + + totalChangedFiles?: number; + + /** + * the total number of unpushed changes + */ + totalUnpushedCommits?: number; + + /** + * unpushed_commits is an array of unpushed changes in the environment, possibly + * truncated + */ + unpushedCommits?: Array<string>; + } + + export namespace Git { + export interface ChangedFile { + /** + * ChangeType is the type of change that happened to the file + */ + changeType?: + | 'CHANGE_TYPE_UNSPECIFIED' + | 'CHANGE_TYPE_ADDED' + | 'CHANGE_TYPE_MODIFIED' + | 'CHANGE_TYPE_DELETED' + | 'CHANGE_TYPE_RENAMED' + | 'CHANGE_TYPE_COPIED' + | 'CHANGE_TYPE_UPDATED_BUT_UNMERGED' + | 'CHANGE_TYPE_UNTRACKED'; + + /** + * path is the path of the file + */ + path?: string; + } + } + } + + /** + * devcontainer contains the status of the devcontainer. + */ + export interface Devcontainer { + /** + * container_id is the ID of the container. + */ + containerId?: string; + + /** + * container_name is the name of the container that is used to connect to the + * devcontainer + */ + containerName?: string; + + /** + * devcontainerconfig_in_sync indicates if the devcontainer is up to date w.r.t. + * the devcontainer config file. + */ + devcontainerconfigInSync?: boolean; + + /** + * devcontainer_file_path is the path to the devcontainer file relative to the repo + * root + */ + devcontainerFilePath?: string; + + /** + * devcontainer_file_presence indicates how the devcontainer file is present in the + * repo. + */ + devcontainerFilePresence?: + | 'PRESENCE_UNSPECIFIED' + | 'PRESENCE_GENERATED' + | 'PRESENCE_DISCOVERED' + | 'PRESENCE_SPECIFIED'; + + /** + * failure_message contains the reason the devcontainer failed to operate. + */ + failureMessage?: string; + + /** + * phase is the current phase of the devcontainer + */ + phase?: 'PHASE_UNSPECIFIED' | 'PHASE_CREATING' | 'PHASE_RUNNING' | 'PHASE_STOPPED' | 'PHASE_FAILED'; + + /** + * remote_user is the user that is used to connect to the devcontainer + */ + remoteUser?: string; + + /** + * remote_workspace_folder is the folder that is used to connect to the + * devcontainer + */ + remoteWorkspaceFolder?: string; + + /** + * secrets_in_sync indicates if the secrets are up to date w.r.t. the running + * devcontainer. + */ + secretsInSync?: boolean; + + /** + * session is the session that is currently active in the devcontainer. + */ + session?: string; + + /** + * warning_message contains warnings, e.g. when the devcontainer is present but not + * in the expected state. + */ + warningMessage?: string; + } + + /** + * environment_url contains the URL at which the environment can be accessed. This + * field is only set if the environment is running. + */ + export interface EnvironmentURLs { + /** + * logs is the URL at which the environment logs can be accessed. + */ + logs?: string; + + ports?: Array<EnvironmentURLs.Port>; + + /** + * SSH is the URL at which the environment can be accessed via SSH. + */ + ssh?: EnvironmentURLs.SSH; + } + + export namespace EnvironmentURLs { + export interface Port { + /** + * port is the port number of the environment port + */ + port?: number; + + /** + * url is the URL at which the environment port can be accessed + */ + url?: string; + } + + /** + * SSH is the URL at which the environment can be accessed via SSH. + */ + export interface SSH { + url?: string; + } + } + + /** + * machine contains the status of the environment machine + */ + export interface Machine { + /** + * failure_message contains the reason the machine failed to operate. + */ + failureMessage?: string; + + /** + * phase is the current phase of the environment machine + */ + phase?: + | 'PHASE_UNSPECIFIED' + | 'PHASE_CREATING' + | 'PHASE_STARTING' + | 'PHASE_RUNNING' + | 'PHASE_STOPPING' + | 'PHASE_STOPPED' + | 'PHASE_DELETING' + | 'PHASE_DELETED'; + + /** + * session is the session that is currently active in the machine. + */ + session?: string; + + /** + * timeout contains the reason the environment has timed out. If this field is + * empty, the environment has not timed out. + */ + timeout?: string; + + /** + * versions contains the versions of components in the machine. + */ + versions?: Machine.Versions; + + /** + * warning_message contains warnings, e.g. when the machine is present but not in + * the expected state. + */ + warningMessage?: string; + } + + export namespace Machine { + /** + * versions contains the versions of components in the machine. + */ + export interface Versions { + supervisorCommit?: string; + + supervisorVersion?: string; + } + } + + /** + * runner_ack contains the acknowledgement from the runner that is has received the + * environment spec. + */ + export interface RunnerAck { + message?: string; + + specVersion?: string; + + statusCode?: + | 'STATUS_CODE_UNSPECIFIED' + | 'STATUS_CODE_OK' + | 'STATUS_CODE_INVALID_RESOURCE' + | 'STATUS_CODE_FAILED_PRECONDITION'; + } + + export interface Secret { + /** + * id is the unique identifier of the secret. + */ + id?: string; + + /** + * failure_message contains the reason the secret failed to be materialize. + */ + failureMessage?: string; + + phase?: + | 'CONTENT_PHASE_UNSPECIFIED' + | 'CONTENT_PHASE_CREATING' + | 'CONTENT_PHASE_INITIALIZING' + | 'CONTENT_PHASE_READY' + | 'CONTENT_PHASE_UPDATING' + | 'CONTENT_PHASE_FAILED'; + + secretName?: string; + + /** + * session is the session that is currently active in the environment. + */ + session?: string; + + /** + * warning_message contains warnings, e.g. when the secret is present but not in + * the expected state. + */ + warningMessage?: string; + } + + export interface SSHPublicKey { + /** + * id is the unique identifier of the public key + */ + id?: string; + + /** + * phase is the current phase of the public key + */ + phase?: + | 'CONTENT_PHASE_UNSPECIFIED' + | 'CONTENT_PHASE_CREATING' + | 'CONTENT_PHASE_INITIALIZING' + | 'CONTENT_PHASE_READY' + | 'CONTENT_PHASE_UPDATING' + | 'CONTENT_PHASE_FAILED'; + } +} + +export interface EnvironmentCreateResponse { + /** + * +resource get environment + */ + environment: Environment; +} + +export interface EnvironmentRetrieveResponse { + /** + * +resource get environment + */ + environment: Environment; +} + +export type EnvironmentUpdateResponse = unknown; + +export type EnvironmentDeleteResponse = unknown; + +export interface EnvironmentCreateEnvironmentTokenResponse { + /** + * access_token is the token that can be used for environment authentication + */ + accessToken: string; +} + +export interface EnvironmentCreateFromProjectResponse { + /** + * +resource get environment + */ + environment: Environment; +} + +export interface EnvironmentCreateLogsTokenResponse { + /** + * access_token is the token that can be used to access the logs of the environment + */ + accessToken: string; +} + +export type EnvironmentMarkActiveResponse = unknown; + +export type EnvironmentStartResponse = unknown; + +export type EnvironmentStopResponse = unknown; + +export interface EnvironmentCreateParams { + /** + * spec is the configuration of the environment that's required for the to start + * the environment + */ + spec?: EnvironmentSpec; +} + +export interface EnvironmentRetrieveParams { + /** + * environment_id specifies the environment to get + */ + environmentId: string; +} + +export interface EnvironmentUpdateParams { + /** + * environment_id specifies which environment should be updated. + * + * +required + */ + environmentId?: string; + + metadata?: unknown | null; + + spec?: EnvironmentUpdateParams.Spec | null; +} + +export namespace EnvironmentUpdateParams { + export interface Spec { + /** + * automations_file is the automations file spec of the environment + */ + automationsFile?: Spec.AutomationsFile | null; + + content?: Spec.Content | null; + + devcontainer?: Spec.Devcontainer | null; + + /** + * ports controls port sharing + */ + ports?: Array<Spec.Port>; + + /** + * ssh_public_keys are the public keys to update empty array means nothing to + * update + */ + sshPublicKeys?: Array<Spec.SSHPublicKey>; + + /** + * Timeout configures the environment timeout + */ + timeout?: Spec.Timeout | null; + } + + export namespace Spec { + /** + * automations_file is the automations file spec of the environment + */ + export interface AutomationsFile { + /** + * automations_file_path is the path to the automations file that is applied in the + * environment, relative to the repo root. path must not be absolute (start with a + * /): + * + * ``` + * this.matches('^$|^[^/].*') + * ``` + */ + automationsFilePath?: string | null; + + session?: string | null; + } + + export interface Content { + /** + * The Git email address + */ + gitEmail?: string | null; + + /** + * The Git username + */ + gitUsername?: string | null; + + /** + * initializer configures how the environment is to be initialized + */ + initializer?: ProjectsAPI.EnvironmentInitializer | null; + + /** + * session should be changed to trigger a content reinitialization + */ + session?: string | null; + } + + export interface Devcontainer { + /** + * devcontainer_file_path is the path to the devcontainer file relative to the repo + * root path must not be absolute (start with a /): + * + * ``` + * this.matches('^$|^[^/].*') + * ``` + */ + devcontainerFilePath?: string | null; + + /** + * session should be changed to trigger a devcontainer rebuild + */ + session?: string | null; + } + + export interface Port { + /** + * policy of this port + */ + admission?: EnvironmentsAPI.AdmissionLevel; + + /** + * name of this port + */ + name?: string; + + /** + * port number + */ + port?: number; + } + + export interface SSHPublicKey { + /** + * id is the unique identifier of the public key + */ + id?: string; + + /** + * value is the actual public key in the public key file format if not provided, + * the public key will be removed + */ + value?: string | null; + } + + /** + * Timeout configures the environment timeout + */ + export interface Timeout { + /** + * inacitivity is the maximum time of disconnection before the environment is + * stopped or paused. Minimum duration is 30 minutes. Set to 0 to disable. + */ + disconnected?: string | null; + } + } +} + +export interface EnvironmentListParams extends EnvironmentsPageParams { + /** + * Body param: + */ + filter?: EnvironmentListParams.Filter; + + /** + * Body param: pagination contains the pagination options for listing environments + */ + pagination?: EnvironmentListParams.Pagination; +} + +export namespace EnvironmentListParams { + export interface Filter { + /** + * creator_ids filters the response to only Environments created by specified + * members + */ + creatorIds?: Array<string>; + + /** + * project_ids filters the response to only Environments associated with the + * specified projects + */ + projectIds?: Array<string>; + + /** + * runner_ids filters the response to only Environments running on these Runner IDs + */ + runnerIds?: Array<string>; + + /** + * runner_kinds filters the response to only Environments running on these Runner + * Kinds + */ + runnerKinds?: Array<RunnersAPI.RunnerKind>; + + /** + * actual_phases is a list of phases the environment must be in for it to be + * returned in the API call + */ + statusPhases?: Array<EnvironmentsAPI.EnvironmentPhase>; + } + + /** + * pagination contains the pagination options for listing environments + */ + export interface Pagination { + /** + * Token for the next set of results that was returned as next_token of a + * PaginationResponse + */ + token?: string; + + /** + * Page size is the maximum number of results to retrieve per page. Defaults to 25. + * Maximum 100. + */ + pageSize?: number; + } +} + +export interface EnvironmentDeleteParams { + /** + * environment_id specifies the environment that is going to delete. + * + * +required + */ + environmentId?: string; + + /** + * force indicates whether the environment should be deleted forcefully When force + * deleting an Environment, the Environment is removed immediately and environment + * lifecycle is not respected. Force deleting can result in data loss on the + * environment. + */ + force?: boolean; +} + +export interface EnvironmentCreateEnvironmentTokenParams { + /** + * environment_id specifies the environment for which the access token should be + * created. + */ + environmentId: string; +} + +export interface EnvironmentCreateFromProjectParams { + projectId?: string; + + /** + * Spec is the configuration of the environment that's required for the runner to + * start the environment Configuration already defined in the Project will override + * parts of the spec, if set + */ + spec?: EnvironmentSpec; +} + +export interface EnvironmentCreateLogsTokenParams { + /** + * environment_id specifies the environment for which the logs token should be + * created. + * + * +required + */ + environmentId?: string; +} + +export interface EnvironmentMarkActiveParams { + /** + * activity_signal specifies the activity. + */ + activitySignal?: EnvironmentActivitySignal; + + /** + * The ID of the environment to update activity for. + */ + environmentId?: string; +} + +export interface EnvironmentStartParams { + /** + * environment_id specifies which environment should be started. + */ + environmentId?: string; +} + +export interface EnvironmentStopParams { + /** + * environment_id specifies which environment should be stopped. + * + * +required + */ + environmentId?: string; +} + +Environments.Automations = Automations; +Environments.Classes = Classes; + +export declare namespace Environments { + export { + type AdmissionLevel as AdmissionLevel, + type Environment as Environment, + type EnvironmentActivitySignal as EnvironmentActivitySignal, + type EnvironmentMetadata as EnvironmentMetadata, + type EnvironmentPhase as EnvironmentPhase, + type EnvironmentSpec as EnvironmentSpec, + type EnvironmentStatus as EnvironmentStatus, + type EnvironmentCreateResponse as EnvironmentCreateResponse, + type EnvironmentRetrieveResponse as EnvironmentRetrieveResponse, + type EnvironmentUpdateResponse as EnvironmentUpdateResponse, + type EnvironmentDeleteResponse as EnvironmentDeleteResponse, + type EnvironmentCreateEnvironmentTokenResponse as EnvironmentCreateEnvironmentTokenResponse, + type EnvironmentCreateFromProjectResponse as EnvironmentCreateFromProjectResponse, + type EnvironmentCreateLogsTokenResponse as EnvironmentCreateLogsTokenResponse, + type EnvironmentMarkActiveResponse as EnvironmentMarkActiveResponse, + type EnvironmentStartResponse as EnvironmentStartResponse, + type EnvironmentStopResponse as EnvironmentStopResponse, + type EnvironmentsEnvironmentsPage as EnvironmentsEnvironmentsPage, + type EnvironmentCreateParams as EnvironmentCreateParams, + type EnvironmentRetrieveParams as EnvironmentRetrieveParams, + type EnvironmentUpdateParams as EnvironmentUpdateParams, + type EnvironmentListParams as EnvironmentListParams, + type EnvironmentDeleteParams as EnvironmentDeleteParams, + type EnvironmentCreateEnvironmentTokenParams as EnvironmentCreateEnvironmentTokenParams, + type EnvironmentCreateFromProjectParams as EnvironmentCreateFromProjectParams, + type EnvironmentCreateLogsTokenParams as EnvironmentCreateLogsTokenParams, + type EnvironmentMarkActiveParams as EnvironmentMarkActiveParams, + type EnvironmentStartParams as EnvironmentStartParams, + type EnvironmentStopParams as EnvironmentStopParams, + }; + + export { + Automations as Automations, + type AutomationsAPIAutomationsFile as AutomationsFile, + type AutomationUpsertResponse as AutomationUpsertResponse, + type AutomationUpsertParams as AutomationUpsertParams, + }; + + export { Classes as Classes, type ClassListParams as ClassListParams }; +} diff --git a/src/resources/environments/index.ts b/src/resources/environments/index.ts new file mode 100644 index 0000000..4378540 --- /dev/null +++ b/src/resources/environments/index.ts @@ -0,0 +1,41 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export { + Automations, + type AutomationsFile, + type AutomationUpsertResponse, + type AutomationUpsertParams, +} from './automations/index'; +export { Classes, type ClassListParams } from './classes'; +export { + Environments, + type AdmissionLevel, + type Environment, + type EnvironmentActivitySignal, + type EnvironmentMetadata, + type EnvironmentPhase, + type EnvironmentSpec, + type EnvironmentStatus, + type EnvironmentCreateResponse, + type EnvironmentRetrieveResponse, + type EnvironmentUpdateResponse, + type EnvironmentDeleteResponse, + type EnvironmentCreateEnvironmentTokenResponse, + type EnvironmentCreateFromProjectResponse, + type EnvironmentCreateLogsTokenResponse, + type EnvironmentMarkActiveResponse, + type EnvironmentStartResponse, + type EnvironmentStopResponse, + type EnvironmentCreateParams, + type EnvironmentRetrieveParams, + type EnvironmentUpdateParams, + type EnvironmentListParams, + type EnvironmentDeleteParams, + type EnvironmentCreateEnvironmentTokenParams, + type EnvironmentCreateFromProjectParams, + type EnvironmentCreateLogsTokenParams, + type EnvironmentMarkActiveParams, + type EnvironmentStartParams, + type EnvironmentStopParams, + type EnvironmentsEnvironmentsPage, +} from './environments'; diff --git a/src/resources/events.ts b/src/resources/events.ts new file mode 100644 index 0000000..109d1aa --- /dev/null +++ b/src/resources/events.ts @@ -0,0 +1,307 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../core/resource'; +import * as EventsAPI from './events'; +import * as Shared from './shared'; +import { APIPromise } from '../core/api-promise'; +import { EntriesPage, type EntriesPageParams, PagePromise } from '../core/pagination'; +import { buildHeaders } from '../internal/headers'; +import { RequestOptions } from '../internal/request-options'; +import { JSONLDecoder } from '../internal/decoders/jsonl'; + +export class Events extends APIResource { + /** + * Lists audit logs with filtering and pagination options. + * + * Use this method to: + * + * - View audit history + * - Track user actions + * - Monitor system changes + * + * ### Examples + * + * - List all logs: + * + * ```yaml + * pagination: + * pageSize: 20 + * ``` + * + * - Filter by actor: + * + * ```yaml + * filter: + * actorIds: ["d2c94c27-3b76-4a42-b88c-95a85e392c68"] + * actorPrincipals: ["PRINCIPAL_USER"] + * pagination: + * pageSize: 20 + * ``` + */ + list( + params: EventListParams, + options?: RequestOptions, + ): PagePromise<EventListResponsesEntriesPage, EventListResponse> { + const { token, pageSize, ...body } = params; + return this._client.getAPIList('/gitpod.v1.EventService/ListAuditLogs', EntriesPage<EventListResponse>, { + query: { token, pageSize }, + body, + method: 'post', + ...options, + }); + } + + /** + * Streams events for all projects, runners, environments, tasks, and services + * based on the specified scope. + * + * Use this method to: + * + * - Monitor resource changes in real-time + * - Track system events + * - Receive notifications + * + * The scope parameter determines which events to watch: + * + * - Organization scope (default): Watch all organization-wide events including + * projects, runners and environments. Task and service events are not included. + * Use by setting organization=true or omitting the scope. + * - Environment scope: Watch events for a specific environment, including its + * tasks, task executions, and services. Use by setting environment_id to the + * UUID of the environment to watch. + */ + watch(body: EventWatchParams, options?: RequestOptions): APIPromise<JSONLDecoder<EventWatchResponse>> { + return this._client + .post('/gitpod.v1.EventService/WatchEvents', { + body, + ...options, + headers: buildHeaders([ + { 'Content-Type': 'application/jsonl', Accept: 'application/jsonl' }, + options?.headers, + ]), + stream: true, + __binaryResponse: true, + }) + ._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller)) as APIPromise< + JSONLDecoder<EventWatchResponse> + >; + } +} + +export type EventListResponsesEntriesPage = EntriesPage<EventListResponse>; + +export type ResourceOperation = + | 'RESOURCE_OPERATION_UNSPECIFIED' + | 'RESOURCE_OPERATION_CREATE' + | 'RESOURCE_OPERATION_UPDATE' + | 'RESOURCE_OPERATION_DELETE' + | 'RESOURCE_OPERATION_UPDATE_STATUS'; + +export type ResourceType = + | 'RESOURCE_TYPE_UNSPECIFIED' + | 'RESOURCE_TYPE_ENVIRONMENT' + | 'RESOURCE_TYPE_RUNNER' + | 'RESOURCE_TYPE_PROJECT' + | 'RESOURCE_TYPE_TASK' + | 'RESOURCE_TYPE_TASK_EXECUTION' + | 'RESOURCE_TYPE_SERVICE' + | 'RESOURCE_TYPE_ORGANIZATION' + | 'RESOURCE_TYPE_USER' + | 'RESOURCE_TYPE_ENVIRONMENT_CLASS' + | 'RESOURCE_TYPE_RUNNER_SCM_INTEGRATION' + | 'RESOURCE_TYPE_HOST_AUTHENTICATION_TOKEN' + | 'RESOURCE_TYPE_GROUP' + | 'RESOURCE_TYPE_PERSONAL_ACCESS_TOKEN' + | 'RESOURCE_TYPE_USER_PREFERENCE' + | 'RESOURCE_TYPE_SERVICE_ACCOUNT' + | 'RESOURCE_TYPE_SECRET' + | 'RESOURCE_TYPE_SSO_CONFIG' + | 'RESOURCE_TYPE_DOMAIN_VERIFICATION' + | 'RESOURCE_TYPE_AGENT_EXECUTION' + | 'RESOURCE_TYPE_RUNNER_LLM_INTEGRATION' + | 'RESOURCE_TYPE_AGENT' + | 'RESOURCE_TYPE_ENVIRONMENT_SESSION' + | 'RESOURCE_TYPE_USER_SECRET' + | 'RESOURCE_TYPE_ORGANIZATION_POLICY'; + +export interface EventListResponse { + id?: string; + + action?: string; + + actorId?: string; + + actorPrincipal?: Shared.Principal; + + /** + * A Timestamp represents a point in time independent of any time zone or local + * calendar, encoded as a count of seconds and fractions of seconds at nanosecond + * resolution. The count is relative to an epoch at UTC midnight on January 1, + * 1970, in the proleptic Gregorian calendar which extends the Gregorian calendar + * backwards to year one. + * + * All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap + * second table is needed for interpretation, using a + * [24-hour linear smear](https://developers.google.com/time/smear). + * + * The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By + * restricting to that range, we ensure that we can convert to and from + * [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. + * + * # Examples + * + * Example 1: Compute Timestamp from POSIX `time()`. + * + * Timestamp timestamp; + * timestamp.set_seconds(time(NULL)); + * timestamp.set_nanos(0); + * + * Example 2: Compute Timestamp from POSIX `gettimeofday()`. + * + * struct timeval tv; + * gettimeofday(&tv, NULL); + * + * Timestamp timestamp; + * timestamp.set_seconds(tv.tv_sec); + * timestamp.set_nanos(tv.tv_usec * 1000); + * + * Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. + * + * FILETIME ft; + * GetSystemTimeAsFileTime(&ft); + * UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; + * + * // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z + * // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. + * Timestamp timestamp; + * timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); + * timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); + * + * Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. + * + * long millis = System.currentTimeMillis(); + * + * Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) + * .setNanos((int) ((millis % 1000) * 1000000)).build(); + * + * Example 5: Compute Timestamp from Java `Instant.now()`. + * + * Instant now = Instant.now(); + * + * Timestamp timestamp = + * Timestamp.newBuilder().setSeconds(now.getEpochSecond()) + * .setNanos(now.getNano()).build(); + * + * Example 6: Compute Timestamp from current time in Python. + * + * timestamp = Timestamp() + * timestamp.GetCurrentTime() + * + * # JSON Mapping + * + * In JSON format, the Timestamp type is encoded as a string in the + * [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the format is + * "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" where {year} is always + * expressed using four digits while {month}, {day}, {hour}, {min}, and {sec} are + * zero-padded to two digits each. The fractional seconds, which can go up to 9 + * digits (i.e. up to 1 nanosecond resolution), are optional. The "Z" suffix + * indicates the timezone ("UTC"); the timezone is required. A proto3 JSON + * serializer should always use UTC (as indicated by "Z") when printing the + * Timestamp type and a proto3 JSON parser should be able to accept both UTC and + * other timezones (as indicated by an offset). + * + * For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past 01:30 UTC on + * January 15, 2017. + * + * In JavaScript, one can convert a Date object to this format using the standard + * [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) + * method. In Python, a standard `datetime.datetime` object can be converted to + * this format using + * [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with the + * time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use the + * Joda Time's + * [`ISODateTimeFormat.dateTime()`](<http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime()>) + * to obtain a formatter capable of generating timestamps in this format. + */ + createdAt?: string; + + subjectId?: string; + + subjectType?: ResourceType; +} + +export interface EventWatchResponse { + operation?: ResourceOperation; + + resourceId?: string; + + resourceType?: ResourceType; +} + +export interface EventListParams extends EntriesPageParams { + /** + * Body param: + */ + filter?: EventListParams.Filter; + + /** + * Body param: pagination contains the pagination options for listing environments + */ + pagination?: EventListParams.Pagination; +} + +export namespace EventListParams { + export interface Filter { + actorIds?: Array<string>; + + actorPrincipals?: Array<Shared.Principal>; + + subjectIds?: Array<string>; + + subjectTypes?: Array<EventsAPI.ResourceType>; + } + + /** + * pagination contains the pagination options for listing environments + */ + export interface Pagination { + /** + * Token for the next set of results that was returned as next_token of a + * PaginationResponse + */ + token?: string; + + /** + * Page size is the maximum number of results to retrieve per page. Defaults to 25. + * Maximum 100. + */ + pageSize?: number; + } +} + +export interface EventWatchParams { + /** + * Environment scope produces events for the environment itself, all tasks, task + * executions, and services associated with that environment. + */ + environmentId?: string; + + /** + * Organization scope produces events for all projects, runners and environments + * the caller can see within their organization. No task, task execution or service + * events are produed. + */ + organization?: boolean; +} + +export declare namespace Events { + export { + type ResourceOperation as ResourceOperation, + type ResourceType as ResourceType, + type EventListResponse as EventListResponse, + type EventWatchResponse as EventWatchResponse, + type EventListResponsesEntriesPage as EventListResponsesEntriesPage, + type EventListParams as EventListParams, + type EventWatchParams as EventWatchParams, + }; +} diff --git a/src/resources/groups.ts b/src/resources/groups.ts new file mode 100644 index 0000000..56384a4 --- /dev/null +++ b/src/resources/groups.ts @@ -0,0 +1,281 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../core/resource'; +import { GroupsPage, type GroupsPageParams, PagePromise } from '../core/pagination'; +import { RequestOptions } from '../internal/request-options'; + +export class Groups extends APIResource { + /** + * Lists groups with optional pagination. + * + * Use this method to: + * + * - View all groups + * - Check group memberships + * - Monitor group configurations + * - Audit group access + * + * ### Examples + * + * - List all groups: + * + * Shows all groups with pagination. + * + * ```yaml + * pagination: + * pageSize: 20 + * ``` + * + * - List with custom page size: + * + * Shows groups with specified page size. + * + * ```yaml + * pagination: + * pageSize: 50 + * token: "next-page-token-from-previous-response" + * ``` + */ + list(params: GroupListParams, options?: RequestOptions): PagePromise<GroupsGroupsPage, Group> { + const { token, pageSize, ...body } = params; + return this._client.getAPIList('/gitpod.v1.GroupService/ListGroups', GroupsPage<Group>, { + query: { token, pageSize }, + body, + method: 'post', + ...options, + }); + } +} + +export type GroupsGroupsPage = GroupsPage<Group>; + +export interface Group { + id?: string; + + /** + * A Timestamp represents a point in time independent of any time zone or local + * calendar, encoded as a count of seconds and fractions of seconds at nanosecond + * resolution. The count is relative to an epoch at UTC midnight on January 1, + * 1970, in the proleptic Gregorian calendar which extends the Gregorian calendar + * backwards to year one. + * + * All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap + * second table is needed for interpretation, using a + * [24-hour linear smear](https://developers.google.com/time/smear). + * + * The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By + * restricting to that range, we ensure that we can convert to and from + * [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. + * + * # Examples + * + * Example 1: Compute Timestamp from POSIX `time()`. + * + * Timestamp timestamp; + * timestamp.set_seconds(time(NULL)); + * timestamp.set_nanos(0); + * + * Example 2: Compute Timestamp from POSIX `gettimeofday()`. + * + * struct timeval tv; + * gettimeofday(&tv, NULL); + * + * Timestamp timestamp; + * timestamp.set_seconds(tv.tv_sec); + * timestamp.set_nanos(tv.tv_usec * 1000); + * + * Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. + * + * FILETIME ft; + * GetSystemTimeAsFileTime(&ft); + * UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; + * + * // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z + * // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. + * Timestamp timestamp; + * timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); + * timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); + * + * Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. + * + * long millis = System.currentTimeMillis(); + * + * Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) + * .setNanos((int) ((millis % 1000) * 1000000)).build(); + * + * Example 5: Compute Timestamp from Java `Instant.now()`. + * + * Instant now = Instant.now(); + * + * Timestamp timestamp = + * Timestamp.newBuilder().setSeconds(now.getEpochSecond()) + * .setNanos(now.getNano()).build(); + * + * Example 6: Compute Timestamp from current time in Python. + * + * timestamp = Timestamp() + * timestamp.GetCurrentTime() + * + * # JSON Mapping + * + * In JSON format, the Timestamp type is encoded as a string in the + * [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the format is + * "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" where {year} is always + * expressed using four digits while {month}, {day}, {hour}, {min}, and {sec} are + * zero-padded to two digits each. The fractional seconds, which can go up to 9 + * digits (i.e. up to 1 nanosecond resolution), are optional. The "Z" suffix + * indicates the timezone ("UTC"); the timezone is required. A proto3 JSON + * serializer should always use UTC (as indicated by "Z") when printing the + * Timestamp type and a proto3 JSON parser should be able to accept both UTC and + * other timezones (as indicated by an offset). + * + * For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past 01:30 UTC on + * January 15, 2017. + * + * In JavaScript, one can convert a Date object to this format using the standard + * [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) + * method. In Python, a standard `datetime.datetime` object can be converted to + * this format using + * [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with the + * time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use the + * Joda Time's + * [`ISODateTimeFormat.dateTime()`](<http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime()>) + * to obtain a formatter capable of generating timestamps in this format. + */ + createdAt?: string; + + name?: string; + + organizationId?: string; + + /** + * system_managed indicates that this group is created by the system automatically + */ + systemManaged?: boolean; + + /** + * A Timestamp represents a point in time independent of any time zone or local + * calendar, encoded as a count of seconds and fractions of seconds at nanosecond + * resolution. The count is relative to an epoch at UTC midnight on January 1, + * 1970, in the proleptic Gregorian calendar which extends the Gregorian calendar + * backwards to year one. + * + * All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap + * second table is needed for interpretation, using a + * [24-hour linear smear](https://developers.google.com/time/smear). + * + * The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By + * restricting to that range, we ensure that we can convert to and from + * [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. + * + * # Examples + * + * Example 1: Compute Timestamp from POSIX `time()`. + * + * Timestamp timestamp; + * timestamp.set_seconds(time(NULL)); + * timestamp.set_nanos(0); + * + * Example 2: Compute Timestamp from POSIX `gettimeofday()`. + * + * struct timeval tv; + * gettimeofday(&tv, NULL); + * + * Timestamp timestamp; + * timestamp.set_seconds(tv.tv_sec); + * timestamp.set_nanos(tv.tv_usec * 1000); + * + * Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. + * + * FILETIME ft; + * GetSystemTimeAsFileTime(&ft); + * UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; + * + * // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z + * // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. + * Timestamp timestamp; + * timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); + * timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); + * + * Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. + * + * long millis = System.currentTimeMillis(); + * + * Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) + * .setNanos((int) ((millis % 1000) * 1000000)).build(); + * + * Example 5: Compute Timestamp from Java `Instant.now()`. + * + * Instant now = Instant.now(); + * + * Timestamp timestamp = + * Timestamp.newBuilder().setSeconds(now.getEpochSecond()) + * .setNanos(now.getNano()).build(); + * + * Example 6: Compute Timestamp from current time in Python. + * + * timestamp = Timestamp() + * timestamp.GetCurrentTime() + * + * # JSON Mapping + * + * In JSON format, the Timestamp type is encoded as a string in the + * [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the format is + * "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" where {year} is always + * expressed using four digits while {month}, {day}, {hour}, {min}, and {sec} are + * zero-padded to two digits each. The fractional seconds, which can go up to 9 + * digits (i.e. up to 1 nanosecond resolution), are optional. The "Z" suffix + * indicates the timezone ("UTC"); the timezone is required. A proto3 JSON + * serializer should always use UTC (as indicated by "Z") when printing the + * Timestamp type and a proto3 JSON parser should be able to accept both UTC and + * other timezones (as indicated by an offset). + * + * For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past 01:30 UTC on + * January 15, 2017. + * + * In JavaScript, one can convert a Date object to this format using the standard + * [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) + * method. In Python, a standard `datetime.datetime` object can be converted to + * this format using + * [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with the + * time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use the + * Joda Time's + * [`ISODateTimeFormat.dateTime()`](<http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime()>) + * to obtain a formatter capable of generating timestamps in this format. + */ + updatedAt?: string; +} + +export interface GroupListParams extends GroupsPageParams { + /** + * Body param: pagination contains the pagination options for listing groups + */ + pagination?: GroupListParams.Pagination; +} + +export namespace GroupListParams { + /** + * pagination contains the pagination options for listing groups + */ + export interface Pagination { + /** + * Token for the next set of results that was returned as next_token of a + * PaginationResponse + */ + token?: string; + + /** + * Page size is the maximum number of results to retrieve per page. Defaults to 25. + * Maximum 100. + */ + pageSize?: number; + } +} + +export declare namespace Groups { + export { + type Group as Group, + type GroupsGroupsPage as GroupsGroupsPage, + type GroupListParams as GroupListParams, + }; +} diff --git a/src/resources/identity.ts b/src/resources/identity.ts new file mode 100644 index 0000000..d1fa01f --- /dev/null +++ b/src/resources/identity.ts @@ -0,0 +1,152 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../core/resource'; +import * as Shared from './shared'; +import { APIPromise } from '../core/api-promise'; +import { RequestOptions } from '../internal/request-options'; + +export class Identity extends APIResource { + /** + * Exchanges an exchange token for a new access token. + * + * Use this method to: + * + * - Convert exchange tokens to access tokens + * - Obtain new access credentials + * - Complete token exchange flows + * + * ### Examples + * + * - Exchange token: + * + * Trades an exchange token for an access token. + * + * ```yaml + * exchangeToken: "exchange-token-value" + * ``` + */ + exchangeToken( + body: IdentityExchangeTokenParams, + options?: RequestOptions, + ): APIPromise<IdentityExchangeTokenResponse> { + return this._client.post('/gitpod.v1.IdentityService/ExchangeToken', { body, ...options }); + } + + /** + * Retrieves information about the currently authenticated identity. + * + * Use this method to: + * + * - Get current user information + * - Check authentication status + * - Retrieve organization context + * - Validate authentication principal + * + * ### Examples + * + * - Get current identity: + * + * Retrieves details about the authenticated user. + * + * ```yaml + * {} + * ``` + */ + getAuthenticatedIdentity( + body: IdentityGetAuthenticatedIdentityParams, + options?: RequestOptions, + ): APIPromise<IdentityGetAuthenticatedIdentityResponse> { + return this._client.post('/gitpod.v1.IdentityService/GetAuthenticatedIdentity', { body, ...options }); + } + + /** + * Gets an ID token for authenticating with other services. + * + * Use this method to: + * + * - Obtain authentication tokens for service-to-service calls + * - Access protected resources + * - Generate scoped access tokens + * + * ### Examples + * + * - Get token for single service: + * + * Retrieves a token for authenticating with one service. + * + * ```yaml + * audience: + * - "https://api.gitpod.io" + * ``` + * + * - Get token for multiple services: + * + * Retrieves a token valid for multiple services. + * + * ```yaml + * audience: + * - "https://api.gitpod.io" + * - "https://ws.gitpod.io" + * ``` + */ + getIDToken( + body: IdentityGetIDTokenParams, + options?: RequestOptions, + ): APIPromise<IdentityGetIDTokenResponse> { + return this._client.post('/gitpod.v1.IdentityService/GetIDToken', { body, ...options }); + } +} + +export type IDTokenVersion = 'ID_TOKEN_VERSION_UNSPECIFIED' | 'ID_TOKEN_VERSION_V1' | 'ID_TOKEN_VERSION_V2'; + +export interface IdentityExchangeTokenResponse { + /** + * access_token is the new access token + */ + accessToken?: string; +} + +export interface IdentityGetAuthenticatedIdentityResponse { + organizationId?: string; + + /** + * subject is the identity of the current user + */ + subject?: Shared.Subject; +} + +export interface IdentityGetIDTokenResponse { + token?: string; +} + +export interface IdentityExchangeTokenParams { + /** + * exchange_token is the token to exchange + */ + exchangeToken?: string; +} + +export interface IdentityGetAuthenticatedIdentityParams { + empty?: boolean; +} + +export interface IdentityGetIDTokenParams { + audience?: Array<string>; + + /** + * version is the version of the ID token. + */ + version?: IDTokenVersion; +} + +export declare namespace Identity { + export { + type IDTokenVersion as IDTokenVersion, + type IdentityExchangeTokenResponse as IdentityExchangeTokenResponse, + type IdentityGetAuthenticatedIdentityResponse as IdentityGetAuthenticatedIdentityResponse, + type IdentityGetIDTokenResponse as IdentityGetIDTokenResponse, + type IdentityExchangeTokenParams as IdentityExchangeTokenParams, + type IdentityGetAuthenticatedIdentityParams as IdentityGetAuthenticatedIdentityParams, + type IdentityGetIDTokenParams as IdentityGetIDTokenParams, + }; +} diff --git a/src/resources/index.ts b/src/resources/index.ts new file mode 100644 index 0000000..664e230 --- /dev/null +++ b/src/resources/index.ts @@ -0,0 +1,182 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export * from './shared'; +export { + Accounts, + type Account, + type AccountMembership, + type JoinableOrganization, + type LoginProvider, + type AccountRetrieveResponse, + type AccountDeleteResponse, + type AccountGetSSOLoginURLResponse, + type AccountRetrieveParams, + type AccountDeleteParams, + type AccountGetSSOLoginURLParams, + type AccountListLoginProvidersParams, + type LoginProvidersLoginProvidersPage, +} from './accounts'; +export { + Editors, + type Editor, + type EditorRetrieveResponse, + type EditorResolveURLResponse, + type EditorRetrieveParams, + type EditorListParams, + type EditorResolveURLParams, + type EditorsEditorsPage, +} from './editors'; +export { + Environments, + type AdmissionLevel, + type Environment, + type EnvironmentActivitySignal, + type EnvironmentMetadata, + type EnvironmentPhase, + type EnvironmentSpec, + type EnvironmentStatus, + type EnvironmentCreateResponse, + type EnvironmentRetrieveResponse, + type EnvironmentUpdateResponse, + type EnvironmentDeleteResponse, + type EnvironmentCreateEnvironmentTokenResponse, + type EnvironmentCreateFromProjectResponse, + type EnvironmentCreateLogsTokenResponse, + type EnvironmentMarkActiveResponse, + type EnvironmentStartResponse, + type EnvironmentStopResponse, + type EnvironmentCreateParams, + type EnvironmentRetrieveParams, + type EnvironmentUpdateParams, + type EnvironmentListParams, + type EnvironmentDeleteParams, + type EnvironmentCreateEnvironmentTokenParams, + type EnvironmentCreateFromProjectParams, + type EnvironmentCreateLogsTokenParams, + type EnvironmentMarkActiveParams, + type EnvironmentStartParams, + type EnvironmentStopParams, + type EnvironmentsEnvironmentsPage, +} from './environments/environments'; +export { + Events, + type ResourceOperation, + type ResourceType, + type EventListResponse, + type EventWatchResponse, + type EventListParams, + type EventWatchParams, + type EventListResponsesEntriesPage, +} from './events'; +export { Groups, type Group, type GroupListParams, type GroupsGroupsPage } from './groups'; +export { + Identity, + type IDTokenVersion, + type IdentityExchangeTokenResponse, + type IdentityGetAuthenticatedIdentityResponse, + type IdentityGetIDTokenResponse, + type IdentityExchangeTokenParams, + type IdentityGetAuthenticatedIdentityParams, + type IdentityGetIDTokenParams, +} from './identity'; +export { + Organizations, + type InviteDomains, + type Organization, + type OrganizationMember, + type OrganizationTier, + type OrganizationCreateResponse, + type OrganizationRetrieveResponse, + type OrganizationUpdateResponse, + type OrganizationDeleteResponse, + type OrganizationJoinResponse, + type OrganizationLeaveResponse, + type OrganizationSetRoleResponse, + type OrganizationCreateParams, + type OrganizationRetrieveParams, + type OrganizationUpdateParams, + type OrganizationDeleteParams, + type OrganizationJoinParams, + type OrganizationLeaveParams, + type OrganizationListMembersParams, + type OrganizationSetRoleParams, + type OrganizationMembersMembersPage, +} from './organizations/organizations'; +export { + Projects, + type EnvironmentInitializer, + type Project, + type ProjectEnvironmentClass, + type ProjectMetadata, + type ProjectCreateResponse, + type ProjectRetrieveResponse, + type ProjectUpdateResponse, + type ProjectDeleteResponse, + type ProjectCreateFromEnvironmentResponse, + type ProjectCreateParams, + type ProjectRetrieveParams, + type ProjectUpdateParams, + type ProjectListParams, + type ProjectDeleteParams, + type ProjectCreateFromEnvironmentParams, + type ProjectsProjectsPage, +} from './projects/projects'; +export { + Runners, + type LogLevel, + type MetricsConfiguration, + type Runner, + type RunnerCapability, + type RunnerConfiguration, + type RunnerKind, + type RunnerPhase, + type RunnerProvider, + type RunnerReleaseChannel, + type RunnerSpec, + type RunnerStatus, + type RunnerCreateResponse, + type RunnerRetrieveResponse, + type RunnerUpdateResponse, + type RunnerDeleteResponse, + type RunnerCheckAuthenticationForHostResponse, + type RunnerCreateRunnerTokenResponse, + type RunnerParseContextURLResponse, + type RunnerCreateParams, + type RunnerRetrieveParams, + type RunnerUpdateParams, + type RunnerListParams, + type RunnerDeleteParams, + type RunnerCheckAuthenticationForHostParams, + type RunnerCreateRunnerTokenParams, + type RunnerParseContextURLParams, + type RunnersRunnersPage, +} from './runners/runners'; +export { + Secrets, + type Secret, + type SecretScope, + type SecretCreateResponse, + type SecretDeleteResponse, + type SecretGetValueResponse, + type SecretUpdateValueResponse, + type SecretCreateParams, + type SecretListParams, + type SecretDeleteParams, + type SecretGetValueParams, + type SecretUpdateValueParams, + type SecretsSecretsPage, +} from './secrets'; +export { + Usage, + type EnvironmentSession, + type UsageListEnvironmentSessionsParams, + type EnvironmentSessionsSessionsPage, +} from './usage'; +export { + Users, + type User, + type UserGetAuthenticatedUserResponse, + type UserSetSuspendedResponse, + type UserGetAuthenticatedUserParams, + type UserSetSuspendedParams, +} from './users/users'; diff --git a/src/resources/organizations.ts b/src/resources/organizations.ts new file mode 100644 index 0000000..61ddaf1 --- /dev/null +++ b/src/resources/organizations.ts @@ -0,0 +1,3 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export * from './organizations/index'; diff --git a/src/resources/organizations/domain-verifications.ts b/src/resources/organizations/domain-verifications.ts new file mode 100644 index 0000000..51e3a9e --- /dev/null +++ b/src/resources/organizations/domain-verifications.ts @@ -0,0 +1,449 @@ +// 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 { + DomainVerificationsPage, + type DomainVerificationsPageParams, + PagePromise, +} from '../../core/pagination'; +import { RequestOptions } from '../../internal/request-options'; + +export class DomainVerifications extends APIResource { + /** + * Initiates domain verification process to enable organization features. + * + * Use this method to: + * + * - Start domain ownership verification + * - Enable automatic team joining + * - Set up SSO restrictions + * - Configure email-based policies + * + * ### Examples + * + * - Verify primary domain: + * + * Starts verification for main company domain. + * + * ```yaml + * organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + * domain: "acme-corp.com" + * ``` + * + * - Verify subsidiary domain: + * + * Adds verification for additional company domain. + * + * ```yaml + * organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + * domain: "acme-subsidiary.com" + * ``` + */ + create( + body: DomainVerificationCreateParams, + options?: RequestOptions, + ): APIPromise<DomainVerificationCreateResponse> { + return this._client.post('/gitpod.v1.OrganizationService/CreateDomainVerification', { body, ...options }); + } + + /** + * Retrieves the status of a domain verification request. + * + * Use this method to: + * + * - Check verification progress + * - View verification requirements + * - Monitor domain status + * + * ### Examples + * + * - Get verification status: + * + * Checks the current state of a domain verification. + * + * ```yaml + * domainVerificationId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + * ``` + */ + retrieve( + body: DomainVerificationRetrieveParams, + options?: RequestOptions, + ): APIPromise<DomainVerificationRetrieveResponse> { + return this._client.post('/gitpod.v1.OrganizationService/GetDomainVerification', { body, ...options }); + } + + /** + * Lists and monitors domain verification status across an organization. + * + * Use this method to: + * + * - Track verification progress + * - View all verified domains + * - Monitor pending verifications + * - Audit domain settings + * + * ### Examples + * + * - List all verifications: + * + * Shows all domain verifications regardless of status. + * + * ```yaml + * organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + * pagination: + * pageSize: 20 + * ``` + * + * - List with pagination: + * + * Retrieves next page of verifications. + * + * ```yaml + * organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + * pagination: + * pageSize: 20 + * token: "next-page-token-from-previous-response" + * ``` + */ + list( + params: DomainVerificationListParams, + options?: RequestOptions, + ): PagePromise<DomainVerificationsDomainVerificationsPage, DomainVerification> { + const { token, pageSize, ...body } = params; + return this._client.getAPIList( + '/gitpod.v1.OrganizationService/ListDomainVerifications', + DomainVerificationsPage<DomainVerification>, + { query: { token, pageSize }, body, method: 'post', ...options }, + ); + } + + /** + * Removes a domain verification request. + * + * Use this method to: + * + * - Cancel pending verifications + * - Remove verified domains + * - Clean up unused domain records + * + * ### Examples + * + * - Delete verification: + * + * Removes a domain verification request. + * + * ```yaml + * domainVerificationId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + * ``` + */ + delete(body: DomainVerificationDeleteParams, options?: RequestOptions): APIPromise<unknown> { + return this._client.post('/gitpod.v1.OrganizationService/DeleteDomainVerification', { body, ...options }); + } + + /** + * Verifies domain ownership for an organization. + * + * Use this method to: + * + * - Complete domain verification process + * - Enable domain-based features + * - Validate DNS configuration + * + * ### Examples + * + * - Verify domain ownership: + * + * Verifies ownership after DNS records are configured. + * + * ```yaml + * domainVerificationId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + * ``` + */ + verify( + body: DomainVerificationVerifyParams, + options?: RequestOptions, + ): APIPromise<DomainVerificationVerifyResponse> { + return this._client.post('/gitpod.v1.OrganizationService/VerifyDomain', { body, ...options }); + } +} + +export type DomainVerificationsDomainVerificationsPage = DomainVerificationsPage<DomainVerification>; + +export interface DomainVerification { + id: string; + + domain: string; + + organizationId: string; + + state: DomainVerificationState; + + /** + * A Timestamp represents a point in time independent of any time zone or local + * calendar, encoded as a count of seconds and fractions of seconds at nanosecond + * resolution. The count is relative to an epoch at UTC midnight on January 1, + * 1970, in the proleptic Gregorian calendar which extends the Gregorian calendar + * backwards to year one. + * + * All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap + * second table is needed for interpretation, using a + * [24-hour linear smear](https://developers.google.com/time/smear). + * + * The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By + * restricting to that range, we ensure that we can convert to and from + * [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. + * + * # Examples + * + * Example 1: Compute Timestamp from POSIX `time()`. + * + * Timestamp timestamp; + * timestamp.set_seconds(time(NULL)); + * timestamp.set_nanos(0); + * + * Example 2: Compute Timestamp from POSIX `gettimeofday()`. + * + * struct timeval tv; + * gettimeofday(&tv, NULL); + * + * Timestamp timestamp; + * timestamp.set_seconds(tv.tv_sec); + * timestamp.set_nanos(tv.tv_usec * 1000); + * + * Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. + * + * FILETIME ft; + * GetSystemTimeAsFileTime(&ft); + * UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; + * + * // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z + * // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. + * Timestamp timestamp; + * timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); + * timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); + * + * Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. + * + * long millis = System.currentTimeMillis(); + * + * Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) + * .setNanos((int) ((millis % 1000) * 1000000)).build(); + * + * Example 5: Compute Timestamp from Java `Instant.now()`. + * + * Instant now = Instant.now(); + * + * Timestamp timestamp = + * Timestamp.newBuilder().setSeconds(now.getEpochSecond()) + * .setNanos(now.getNano()).build(); + * + * Example 6: Compute Timestamp from current time in Python. + * + * timestamp = Timestamp() + * timestamp.GetCurrentTime() + * + * # JSON Mapping + * + * In JSON format, the Timestamp type is encoded as a string in the + * [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the format is + * "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" where {year} is always + * expressed using four digits while {month}, {day}, {hour}, {min}, and {sec} are + * zero-padded to two digits each. The fractional seconds, which can go up to 9 + * digits (i.e. up to 1 nanosecond resolution), are optional. The "Z" suffix + * indicates the timezone ("UTC"); the timezone is required. A proto3 JSON + * serializer should always use UTC (as indicated by "Z") when printing the + * Timestamp type and a proto3 JSON parser should be able to accept both UTC and + * other timezones (as indicated by an offset). + * + * For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past 01:30 UTC on + * January 15, 2017. + * + * In JavaScript, one can convert a Date object to this format using the standard + * [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) + * method. In Python, a standard `datetime.datetime` object can be converted to + * this format using + * [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with the + * time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use the + * Joda Time's + * [`ISODateTimeFormat.dateTime()`](<http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime()>) + * to obtain a formatter capable of generating timestamps in this format. + */ + createdAt?: string; + + verificationToken?: string; + + /** + * A Timestamp represents a point in time independent of any time zone or local + * calendar, encoded as a count of seconds and fractions of seconds at nanosecond + * resolution. The count is relative to an epoch at UTC midnight on January 1, + * 1970, in the proleptic Gregorian calendar which extends the Gregorian calendar + * backwards to year one. + * + * All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap + * second table is needed for interpretation, using a + * [24-hour linear smear](https://developers.google.com/time/smear). + * + * The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By + * restricting to that range, we ensure that we can convert to and from + * [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. + * + * # Examples + * + * Example 1: Compute Timestamp from POSIX `time()`. + * + * Timestamp timestamp; + * timestamp.set_seconds(time(NULL)); + * timestamp.set_nanos(0); + * + * Example 2: Compute Timestamp from POSIX `gettimeofday()`. + * + * struct timeval tv; + * gettimeofday(&tv, NULL); + * + * Timestamp timestamp; + * timestamp.set_seconds(tv.tv_sec); + * timestamp.set_nanos(tv.tv_usec * 1000); + * + * Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. + * + * FILETIME ft; + * GetSystemTimeAsFileTime(&ft); + * UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; + * + * // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z + * // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. + * Timestamp timestamp; + * timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); + * timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); + * + * Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. + * + * long millis = System.currentTimeMillis(); + * + * Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) + * .setNanos((int) ((millis % 1000) * 1000000)).build(); + * + * Example 5: Compute Timestamp from Java `Instant.now()`. + * + * Instant now = Instant.now(); + * + * Timestamp timestamp = + * Timestamp.newBuilder().setSeconds(now.getEpochSecond()) + * .setNanos(now.getNano()).build(); + * + * Example 6: Compute Timestamp from current time in Python. + * + * timestamp = Timestamp() + * timestamp.GetCurrentTime() + * + * # JSON Mapping + * + * In JSON format, the Timestamp type is encoded as a string in the + * [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the format is + * "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" where {year} is always + * expressed using four digits while {month}, {day}, {hour}, {min}, and {sec} are + * zero-padded to two digits each. The fractional seconds, which can go up to 9 + * digits (i.e. up to 1 nanosecond resolution), are optional. The "Z" suffix + * indicates the timezone ("UTC"); the timezone is required. A proto3 JSON + * serializer should always use UTC (as indicated by "Z") when printing the + * Timestamp type and a proto3 JSON parser should be able to accept both UTC and + * other timezones (as indicated by an offset). + * + * For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past 01:30 UTC on + * January 15, 2017. + * + * In JavaScript, one can convert a Date object to this format using the standard + * [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) + * method. In Python, a standard `datetime.datetime` object can be converted to + * this format using + * [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with the + * time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use the + * Joda Time's + * [`ISODateTimeFormat.dateTime()`](<http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime()>) + * to obtain a formatter capable of generating timestamps in this format. + */ + verifiedAt?: string; +} + +export type DomainVerificationState = + | 'DOMAIN_VERIFICATION_STATE_UNSPECIFIED' + | 'DOMAIN_VERIFICATION_STATE_PENDING' + | 'DOMAIN_VERIFICATION_STATE_VERIFIED'; + +export interface DomainVerificationCreateResponse { + domainVerification: DomainVerification; +} + +export interface DomainVerificationRetrieveResponse { + domainVerification: DomainVerification; +} + +export type DomainVerificationDeleteResponse = unknown; + +export interface DomainVerificationVerifyResponse { + domainVerification: DomainVerification; +} + +export interface DomainVerificationCreateParams { + domain: string; + + organizationId: string; +} + +export interface DomainVerificationRetrieveParams { + domainVerificationId: string; +} + +export interface DomainVerificationListParams extends DomainVerificationsPageParams { + /** + * Body param: + */ + organizationId: string; + + /** + * Body param: + */ + pagination?: DomainVerificationListParams.Pagination; +} + +export namespace DomainVerificationListParams { + export interface Pagination { + /** + * Token for the next set of results that was returned as next_token of a + * PaginationResponse + */ + token?: string; + + /** + * Page size is the maximum number of results to retrieve per page. Defaults to 25. + * Maximum 100. + */ + pageSize?: number; + } +} + +export interface DomainVerificationDeleteParams { + domainVerificationId: string; +} + +export interface DomainVerificationVerifyParams { + domainVerificationId: string; +} + +export declare namespace DomainVerifications { + export { + type DomainVerification as DomainVerification, + type DomainVerificationState as DomainVerificationState, + type DomainVerificationCreateResponse as DomainVerificationCreateResponse, + type DomainVerificationRetrieveResponse as DomainVerificationRetrieveResponse, + type DomainVerificationDeleteResponse as DomainVerificationDeleteResponse, + type DomainVerificationVerifyResponse as DomainVerificationVerifyResponse, + type DomainVerificationsDomainVerificationsPage as DomainVerificationsDomainVerificationsPage, + type DomainVerificationCreateParams as DomainVerificationCreateParams, + type DomainVerificationRetrieveParams as DomainVerificationRetrieveParams, + type DomainVerificationListParams as DomainVerificationListParams, + type DomainVerificationDeleteParams as DomainVerificationDeleteParams, + type DomainVerificationVerifyParams as DomainVerificationVerifyParams, + }; +} diff --git a/src/resources/organizations/index.ts b/src/resources/organizations/index.ts new file mode 100644 index 0000000..a023d54 --- /dev/null +++ b/src/resources/organizations/index.ts @@ -0,0 +1,74 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export { + DomainVerifications, + type DomainVerification, + type DomainVerificationState, + type DomainVerificationCreateResponse, + type DomainVerificationRetrieveResponse, + type DomainVerificationDeleteResponse, + type DomainVerificationVerifyResponse, + type DomainVerificationCreateParams, + type DomainVerificationRetrieveParams, + type DomainVerificationListParams, + type DomainVerificationDeleteParams, + type DomainVerificationVerifyParams, + type DomainVerificationsDomainVerificationsPage, +} from './domain-verifications'; +export { + Invites, + type OrganizationInvite, + type InviteCreateResponse, + type InviteRetrieveResponse, + type InviteGetSummaryResponse, + type InviteCreateParams, + type InviteRetrieveParams, + type InviteGetSummaryParams, +} from './invites'; +export { + Organizations, + type InviteDomains, + type Organization, + type OrganizationMember, + type OrganizationTier, + type OrganizationCreateResponse, + type OrganizationRetrieveResponse, + type OrganizationUpdateResponse, + type OrganizationDeleteResponse, + type OrganizationJoinResponse, + type OrganizationLeaveResponse, + type OrganizationSetRoleResponse, + type OrganizationCreateParams, + type OrganizationRetrieveParams, + type OrganizationUpdateParams, + type OrganizationDeleteParams, + type OrganizationJoinParams, + type OrganizationLeaveParams, + type OrganizationListMembersParams, + type OrganizationSetRoleParams, + type OrganizationMembersMembersPage, +} from './organizations'; +export { + Policies, + type OrganizationPolicies, + type PolicyRetrieveResponse, + type PolicyUpdateResponse, + type PolicyRetrieveParams, + type PolicyUpdateParams, +} from './policies'; +export { + SSOConfigurations, + type ProviderType, + type SSOConfiguration, + type SSOConfigurationState, + type SSOConfigurationCreateResponse, + type SSOConfigurationRetrieveResponse, + type SSOConfigurationUpdateResponse, + type SSOConfigurationDeleteResponse, + type SSOConfigurationCreateParams, + type SSOConfigurationRetrieveParams, + type SSOConfigurationUpdateParams, + type SSOConfigurationListParams, + type SSOConfigurationDeleteParams, + type SSOConfigurationsSSOConfigurationsPage, +} from './sso-configurations'; diff --git a/src/resources/organizations/invites.ts b/src/resources/organizations/invites.ts new file mode 100644 index 0000000..5dded81 --- /dev/null +++ b/src/resources/organizations/invites.ts @@ -0,0 +1,113 @@ +// 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 { RequestOptions } from '../../internal/request-options'; + +export class Invites extends APIResource { + /** + * Creates an invite link for joining an organization. Any existing + * OrganizationInvites are invalidated and can no longer be used. + * + * Use this method to: + * + * - Generate shareable invite links + * - Manage team growth + * - Control organization access + * + * ### Examples + * + * - Create organization invite: + * + * Generates a new invite link for the organization. + * + * ```yaml + * organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + * ``` + */ + create(body: InviteCreateParams, options?: RequestOptions): APIPromise<InviteCreateResponse> { + return this._client.post('/gitpod.v1.OrganizationService/CreateOrganizationInvite', { body, ...options }); + } + + /** + * GetOrganizationInvite + */ + retrieve(body: InviteRetrieveParams, options?: RequestOptions): APIPromise<InviteRetrieveResponse> { + return this._client.post('/gitpod.v1.OrganizationService/GetOrganizationInvite', { body, ...options }); + } + + /** + * Retrieves organization details and membership info based on an invite link. + * + * Use this method to: + * + * - Preview organization details before joining + * - Validate invite link authenticity + * - Check organization size and activity + * - View team information before accepting + * + * ### Examples + * + * - Get invite summary: + * + * Retrieves organization information from an invite. + * + * ```yaml + * inviteId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + * ``` + */ + getSummary(body: InviteGetSummaryParams, options?: RequestOptions): APIPromise<InviteGetSummaryResponse> { + return this._client.post('/gitpod.v1.OrganizationService/GetOrganizationInviteSummary', { + body, + ...options, + }); + } +} + +export interface OrganizationInvite { + /** + * invite_id is the unique identifier of the invite to join the organization. Use + * JoinOrganization with this ID to join the organization. + */ + inviteId: string; +} + +export interface InviteCreateResponse { + invite: OrganizationInvite; +} + +export interface InviteRetrieveResponse { + invite: OrganizationInvite; +} + +export interface InviteGetSummaryResponse { + organizationId: string; + + organizationMemberCount?: number; + + organizationName?: string; +} + +export interface InviteCreateParams { + organizationId: string; +} + +export interface InviteRetrieveParams { + organizationId: string; +} + +export interface InviteGetSummaryParams { + inviteId: string; +} + +export declare namespace Invites { + export { + type OrganizationInvite as OrganizationInvite, + type InviteCreateResponse as InviteCreateResponse, + type InviteRetrieveResponse as InviteRetrieveResponse, + type InviteGetSummaryResponse as InviteGetSummaryResponse, + type InviteCreateParams as InviteCreateParams, + type InviteRetrieveParams as InviteRetrieveParams, + type InviteGetSummaryParams as InviteGetSummaryParams, + }; +} diff --git a/src/resources/organizations/organizations.ts b/src/resources/organizations/organizations.ts new file mode 100644 index 0000000..2393f17 --- /dev/null +++ b/src/resources/organizations/organizations.ts @@ -0,0 +1,882 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../../core/resource'; +import * as Shared from '../shared'; +import * as DomainVerificationsAPI from './domain-verifications'; +import { + DomainVerification, + DomainVerificationCreateParams, + DomainVerificationCreateResponse, + DomainVerificationDeleteParams, + DomainVerificationDeleteResponse, + DomainVerificationListParams, + DomainVerificationRetrieveParams, + DomainVerificationRetrieveResponse, + DomainVerificationState, + DomainVerificationVerifyParams, + DomainVerificationVerifyResponse, + DomainVerifications, + DomainVerificationsDomainVerificationsPage, +} from './domain-verifications'; +import * as InvitesAPI from './invites'; +import { + InviteCreateParams, + InviteCreateResponse, + InviteGetSummaryParams, + InviteGetSummaryResponse, + InviteRetrieveParams, + InviteRetrieveResponse, + Invites, + OrganizationInvite, +} from './invites'; +import * as PoliciesAPI from './policies'; +import { + OrganizationPolicies, + Policies, + PolicyRetrieveParams, + PolicyRetrieveResponse, + PolicyUpdateParams, + PolicyUpdateResponse, +} from './policies'; +import * as SSOConfigurationsAPI from './sso-configurations'; +import { + ProviderType, + SSOConfiguration, + SSOConfigurationCreateParams, + SSOConfigurationCreateResponse, + SSOConfigurationDeleteParams, + SSOConfigurationDeleteResponse, + SSOConfigurationListParams, + SSOConfigurationRetrieveParams, + SSOConfigurationRetrieveResponse, + SSOConfigurationState, + SSOConfigurationUpdateParams, + SSOConfigurationUpdateResponse, + SSOConfigurations, + SSOConfigurationsSSOConfigurationsPage, +} from './sso-configurations'; +import { APIPromise } from '../../core/api-promise'; +import { MembersPage, type MembersPageParams, PagePromise } from '../../core/pagination'; +import { RequestOptions } from '../../internal/request-options'; + +export class Organizations extends APIResource { + domainVerifications: DomainVerificationsAPI.DomainVerifications = + new DomainVerificationsAPI.DomainVerifications(this._client); + invites: InvitesAPI.Invites = new InvitesAPI.Invites(this._client); + policies: PoliciesAPI.Policies = new PoliciesAPI.Policies(this._client); + ssoConfigurations: SSOConfigurationsAPI.SSOConfigurations = new SSOConfigurationsAPI.SSOConfigurations( + this._client, + ); + + /** + * Creates a new organization with the specified name and settings. + * + * Use this method to: + * + * - Create a new organization for team collaboration + * - Set up automatic domain-based invites for team members + * - Join the organization immediately upon creation + * + * ### Examples + * + * - Create a basic organization: + * + * Creates an organization with just a name. + * + * ```yaml + * name: "Acme Corp Engineering" + * joinOrganization: true + * ``` + * + * - Create with domain-based invites: + * + * Creates an organization that automatically invites users with matching email + * domains. + * + * ```yaml + * name: "Acme Corp" + * joinOrganization: true + * inviteAccountsWithMatchingDomain: true + * ``` + */ + create(body: OrganizationCreateParams, options?: RequestOptions): APIPromise<OrganizationCreateResponse> { + return this._client.post('/gitpod.v1.OrganizationService/CreateOrganization', { body, ...options }); + } + + /** + * Gets details about a specific organization. + * + * Use this method to: + * + * - Retrieve organization settings and configuration + * - Check organization membership status + * - View domain verification settings + * + * ### Examples + * + * - Get organization details: + * + * Retrieves information about a specific organization. + * + * ```yaml + * organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + * ``` + */ + retrieve( + body: OrganizationRetrieveParams, + options?: RequestOptions, + ): APIPromise<OrganizationRetrieveResponse> { + return this._client.post('/gitpod.v1.OrganizationService/GetOrganization', { body, ...options }); + } + + /** + * Updates an organization's settings including name, invite domains, and member + * policies. + * + * Use this method to: + * + * - Modify organization display name + * - Configure email domain restrictions + * - Update organization-wide settings + * - Manage member access policies + * + * ### Examples + * + * - Update basic settings: + * + * Changes organization name and invite domains. + * + * ```yaml + * organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + * name: "New Company Name" + * inviteDomains: + * domains: + * - "company.com" + * - "subsidiary.com" + * ``` + * + * - Remove domain restrictions: + * + * Clears all domain-based invite restrictions. + * + * ```yaml + * organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + * inviteDomains: + * domains: [] + * ``` + */ + update(body: OrganizationUpdateParams, options?: RequestOptions): APIPromise<OrganizationUpdateResponse> { + return this._client.post('/gitpod.v1.OrganizationService/UpdateOrganization', { body, ...options }); + } + + /** + * Permanently deletes an organization. + * + * Use this method to: + * + * - Remove unused organizations + * - Clean up test organizations + * - Complete organization migration + * + * ### Examples + * + * - Delete organization: + * + * Permanently removes an organization and all its data. + * + * ```yaml + * organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + * ``` + */ + delete(body: OrganizationDeleteParams, options?: RequestOptions): APIPromise<unknown> { + return this._client.post('/gitpod.v1.OrganizationService/DeleteOrganization', { body, ...options }); + } + + /** + * Allows users to join an organization through direct ID, invite link, or + * domain-based auto-join. + * + * Use this method to: + * + * - Join an organization via direct ID or invite + * - Join automatically based on email domain + * - Accept organization invitations + * + * ### Examples + * + * - Join via organization ID: + * + * Joins an organization directly when you have the ID. + * + * ```yaml + * organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + * ``` + * + * - Join via invite: + * + * Accepts an organization invitation link. + * + * ```yaml + * inviteId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + * ``` + */ + join(body: OrganizationJoinParams, options?: RequestOptions): APIPromise<OrganizationJoinResponse> { + return this._client.post('/gitpod.v1.OrganizationService/JoinOrganization', { body, ...options }); + } + + /** + * Removes a user from an organization while preserving organization data. + * + * Use this method to: + * + * - Remove yourself from an organization + * - Clean up inactive memberships + * - Transfer project ownership before leaving + * - Manage team transitions + * + * ### Examples + * + * - Leave organization: + * + * Removes user from organization membership. + * + * ```yaml + * userId: "f53d2330-3795-4c5d-a1f3-453121af9c60" + * ``` + * + * Note: Ensure all projects and resources are transferred before leaving. + */ + leave(body: OrganizationLeaveParams, options?: RequestOptions): APIPromise<unknown> { + return this._client.post('/gitpod.v1.OrganizationService/LeaveOrganization', { body, ...options }); + } + + /** + * Lists and filters organization members with optional pagination. + * + * Use this method to: + * + * - View all organization members + * - Monitor member activity + * - Manage team membership + * + * ### Examples + * + * - List active members: + * + * Retrieves active members with pagination. + * + * ```yaml + * organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + * pagination: + * pageSize: 20 + * ``` + * + * - List with pagination: + * + * Retrieves next page of members. + * + * ```yaml + * organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + * pagination: + * pageSize: 50 + * token: "next-page-token-from-previous-response" + * ``` + */ + listMembers( + params: OrganizationListMembersParams, + options?: RequestOptions, + ): PagePromise<OrganizationMembersMembersPage, OrganizationMember> { + const { token, pageSize, ...body } = params; + return this._client.getAPIList( + '/gitpod.v1.OrganizationService/ListMembers', + MembersPage<OrganizationMember>, + { query: { token, pageSize }, body, method: 'post', ...options }, + ); + } + + /** + * Manages organization membership and roles by setting a user's role within the + * organization. + * + * Use this method to: + * + * - Promote members to admin role + * - Change member permissions + * - Demote admins to regular members + * + * ### Examples + * + * - Promote to admin: + * + * Makes a user an organization administrator. + * + * ```yaml + * organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + * userId: "f53d2330-3795-4c5d-a1f3-453121af9c60" + * role: ORGANIZATION_ROLE_ADMIN + * ``` + * + * - Change to member: + * + * Changes a user's role to regular member. + * + * ```yaml + * organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + * userId: "f53d2330-3795-4c5d-a1f3-453121af9c60" + * role: ORGANIZATION_ROLE_MEMBER + * ``` + */ + setRole(body: OrganizationSetRoleParams, options?: RequestOptions): APIPromise<unknown> { + return this._client.post('/gitpod.v1.OrganizationService/SetRole', { body, ...options }); + } +} + +export type OrganizationMembersMembersPage = MembersPage<OrganizationMember>; + +export interface InviteDomains { + /** + * domains is the list of domains that are allowed to join the organization + */ + domains?: Array<string>; +} + +export interface Organization { + id: string; + + /** + * A Timestamp represents a point in time independent of any time zone or local + * calendar, encoded as a count of seconds and fractions of seconds at nanosecond + * resolution. The count is relative to an epoch at UTC midnight on January 1, + * 1970, in the proleptic Gregorian calendar which extends the Gregorian calendar + * backwards to year one. + * + * All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap + * second table is needed for interpretation, using a + * [24-hour linear smear](https://developers.google.com/time/smear). + * + * The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By + * restricting to that range, we ensure that we can convert to and from + * [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. + * + * # Examples + * + * Example 1: Compute Timestamp from POSIX `time()`. + * + * Timestamp timestamp; + * timestamp.set_seconds(time(NULL)); + * timestamp.set_nanos(0); + * + * Example 2: Compute Timestamp from POSIX `gettimeofday()`. + * + * struct timeval tv; + * gettimeofday(&tv, NULL); + * + * Timestamp timestamp; + * timestamp.set_seconds(tv.tv_sec); + * timestamp.set_nanos(tv.tv_usec * 1000); + * + * Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. + * + * FILETIME ft; + * GetSystemTimeAsFileTime(&ft); + * UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; + * + * // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z + * // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. + * Timestamp timestamp; + * timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); + * timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); + * + * Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. + * + * long millis = System.currentTimeMillis(); + * + * Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) + * .setNanos((int) ((millis % 1000) * 1000000)).build(); + * + * Example 5: Compute Timestamp from Java `Instant.now()`. + * + * Instant now = Instant.now(); + * + * Timestamp timestamp = + * Timestamp.newBuilder().setSeconds(now.getEpochSecond()) + * .setNanos(now.getNano()).build(); + * + * Example 6: Compute Timestamp from current time in Python. + * + * timestamp = Timestamp() + * timestamp.GetCurrentTime() + * + * # JSON Mapping + * + * In JSON format, the Timestamp type is encoded as a string in the + * [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the format is + * "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" where {year} is always + * expressed using four digits while {month}, {day}, {hour}, {min}, and {sec} are + * zero-padded to two digits each. The fractional seconds, which can go up to 9 + * digits (i.e. up to 1 nanosecond resolution), are optional. The "Z" suffix + * indicates the timezone ("UTC"); the timezone is required. A proto3 JSON + * serializer should always use UTC (as indicated by "Z") when printing the + * Timestamp type and a proto3 JSON parser should be able to accept both UTC and + * other timezones (as indicated by an offset). + * + * For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past 01:30 UTC on + * January 15, 2017. + * + * In JavaScript, one can convert a Date object to this format using the standard + * [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) + * method. In Python, a standard `datetime.datetime` object can be converted to + * this format using + * [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with the + * time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use the + * Joda Time's + * [`ISODateTimeFormat.dateTime()`](<http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime()>) + * to obtain a formatter capable of generating timestamps in this format. + */ + createdAt: string; + + name: string; + + /** + * The tier of the organization - free or enterprise + */ + tier: OrganizationTier; + + /** + * A Timestamp represents a point in time independent of any time zone or local + * calendar, encoded as a count of seconds and fractions of seconds at nanosecond + * resolution. The count is relative to an epoch at UTC midnight on January 1, + * 1970, in the proleptic Gregorian calendar which extends the Gregorian calendar + * backwards to year one. + * + * All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap + * second table is needed for interpretation, using a + * [24-hour linear smear](https://developers.google.com/time/smear). + * + * The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By + * restricting to that range, we ensure that we can convert to and from + * [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. + * + * # Examples + * + * Example 1: Compute Timestamp from POSIX `time()`. + * + * Timestamp timestamp; + * timestamp.set_seconds(time(NULL)); + * timestamp.set_nanos(0); + * + * Example 2: Compute Timestamp from POSIX `gettimeofday()`. + * + * struct timeval tv; + * gettimeofday(&tv, NULL); + * + * Timestamp timestamp; + * timestamp.set_seconds(tv.tv_sec); + * timestamp.set_nanos(tv.tv_usec * 1000); + * + * Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. + * + * FILETIME ft; + * GetSystemTimeAsFileTime(&ft); + * UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; + * + * // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z + * // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. + * Timestamp timestamp; + * timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); + * timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); + * + * Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. + * + * long millis = System.currentTimeMillis(); + * + * Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) + * .setNanos((int) ((millis % 1000) * 1000000)).build(); + * + * Example 5: Compute Timestamp from Java `Instant.now()`. + * + * Instant now = Instant.now(); + * + * Timestamp timestamp = + * Timestamp.newBuilder().setSeconds(now.getEpochSecond()) + * .setNanos(now.getNano()).build(); + * + * Example 6: Compute Timestamp from current time in Python. + * + * timestamp = Timestamp() + * timestamp.GetCurrentTime() + * + * # JSON Mapping + * + * In JSON format, the Timestamp type is encoded as a string in the + * [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the format is + * "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" where {year} is always + * expressed using four digits while {month}, {day}, {hour}, {min}, and {sec} are + * zero-padded to two digits each. The fractional seconds, which can go up to 9 + * digits (i.e. up to 1 nanosecond resolution), are optional. The "Z" suffix + * indicates the timezone ("UTC"); the timezone is required. A proto3 JSON + * serializer should always use UTC (as indicated by "Z") when printing the + * Timestamp type and a proto3 JSON parser should be able to accept both UTC and + * other timezones (as indicated by an offset). + * + * For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past 01:30 UTC on + * January 15, 2017. + * + * In JavaScript, one can convert a Date object to this format using the standard + * [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) + * method. In Python, a standard `datetime.datetime` object can be converted to + * this format using + * [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with the + * time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use the + * Joda Time's + * [`ISODateTimeFormat.dateTime()`](<http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime()>) + * to obtain a formatter capable of generating timestamps in this format. + */ + updatedAt: string; + + inviteDomains?: InviteDomains; +} + +export interface OrganizationMember { + email: string; + + fullName: string; + + /** + * login_provider is the login provider the user uses to sign in + */ + loginProvider: string; + + /** + * A Timestamp represents a point in time independent of any time zone or local + * calendar, encoded as a count of seconds and fractions of seconds at nanosecond + * resolution. The count is relative to an epoch at UTC midnight on January 1, + * 1970, in the proleptic Gregorian calendar which extends the Gregorian calendar + * backwards to year one. + * + * All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap + * second table is needed for interpretation, using a + * [24-hour linear smear](https://developers.google.com/time/smear). + * + * The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By + * restricting to that range, we ensure that we can convert to and from + * [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. + * + * # Examples + * + * Example 1: Compute Timestamp from POSIX `time()`. + * + * Timestamp timestamp; + * timestamp.set_seconds(time(NULL)); + * timestamp.set_nanos(0); + * + * Example 2: Compute Timestamp from POSIX `gettimeofday()`. + * + * struct timeval tv; + * gettimeofday(&tv, NULL); + * + * Timestamp timestamp; + * timestamp.set_seconds(tv.tv_sec); + * timestamp.set_nanos(tv.tv_usec * 1000); + * + * Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. + * + * FILETIME ft; + * GetSystemTimeAsFileTime(&ft); + * UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; + * + * // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z + * // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. + * Timestamp timestamp; + * timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); + * timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); + * + * Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. + * + * long millis = System.currentTimeMillis(); + * + * Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) + * .setNanos((int) ((millis % 1000) * 1000000)).build(); + * + * Example 5: Compute Timestamp from Java `Instant.now()`. + * + * Instant now = Instant.now(); + * + * Timestamp timestamp = + * Timestamp.newBuilder().setSeconds(now.getEpochSecond()) + * .setNanos(now.getNano()).build(); + * + * Example 6: Compute Timestamp from current time in Python. + * + * timestamp = Timestamp() + * timestamp.GetCurrentTime() + * + * # JSON Mapping + * + * In JSON format, the Timestamp type is encoded as a string in the + * [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the format is + * "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" where {year} is always + * expressed using four digits while {month}, {day}, {hour}, {min}, and {sec} are + * zero-padded to two digits each. The fractional seconds, which can go up to 9 + * digits (i.e. up to 1 nanosecond resolution), are optional. The "Z" suffix + * indicates the timezone ("UTC"); the timezone is required. A proto3 JSON + * serializer should always use UTC (as indicated by "Z") when printing the + * Timestamp type and a proto3 JSON parser should be able to accept both UTC and + * other timezones (as indicated by an offset). + * + * For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past 01:30 UTC on + * January 15, 2017. + * + * In JavaScript, one can convert a Date object to this format using the standard + * [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) + * method. In Python, a standard `datetime.datetime` object can be converted to + * this format using + * [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with the + * time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use the + * Joda Time's + * [`ISODateTimeFormat.dateTime()`](<http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime()>) + * to obtain a formatter capable of generating timestamps in this format. + */ + memberSince: string; + + role: Shared.OrganizationRole; + + status: Shared.UserStatus; + + userId: string; + + avatarUrl?: string; +} + +export type OrganizationTier = + | 'ORGANIZATION_TIER_UNSPECIFIED' + | 'ORGANIZATION_TIER_FREE' + | 'ORGANIZATION_TIER_ENTERPRISE'; + +export interface OrganizationCreateResponse { + /** + * organization is the created organization + */ + organization: Organization; + + /** + * member is the member that joined the org on creation. Only set if specified + * "join_organization" is "true" in the request. + */ + member?: OrganizationMember; +} + +export interface OrganizationRetrieveResponse { + /** + * organization is the requested organization + */ + organization: Organization; +} + +export interface OrganizationUpdateResponse { + /** + * organization is the updated organization + */ + organization: Organization; +} + +export type OrganizationDeleteResponse = unknown; + +export interface OrganizationJoinResponse { + /** + * member is the member that was created by joining the organization. + */ + member: OrganizationMember; +} + +export type OrganizationLeaveResponse = unknown; + +export type OrganizationSetRoleResponse = unknown; + +export interface OrganizationCreateParams { + /** + * name is the organization name + */ + name: string; + + /** + * Should other Accounts with the same domain be automatically invited to the + * organization? + */ + inviteAccountsWithMatchingDomain?: boolean; + + /** + * join_organization decides whether the Identity issuing this request joins the + * org on creation + */ + joinOrganization?: boolean; +} + +export interface OrganizationRetrieveParams { + /** + * organization_id is the unique identifier of the Organization to retreive. + */ + organizationId: string; +} + +export interface OrganizationUpdateParams { + /** + * organization_id is the ID of the organization to update the settings for. + */ + organizationId: string; + + /** + * invite_domains is the domain allowlist of the organization + */ + inviteDomains?: InviteDomains | null; + + /** + * name is the new name of the organization + */ + name?: string | null; +} + +export interface OrganizationDeleteParams { + /** + * organization_id is the ID of the organization to delete + */ + organizationId: string; +} + +export interface OrganizationJoinParams { + /** + * invite_id is the unique identifier of the invite to join the organization. + */ + inviteId?: string; + + /** + * organization_id is the unique identifier of the Organization to join. + */ + organizationId?: string; +} + +export interface OrganizationLeaveParams { + userId: string; +} + +export interface OrganizationListMembersParams extends MembersPageParams { + /** + * Body param: organization_id is the ID of the organization to list members for + */ + organizationId: string; + + /** + * Body param: pagination contains the pagination options for listing members + */ + pagination?: OrganizationListMembersParams.Pagination; +} + +export namespace OrganizationListMembersParams { + /** + * pagination contains the pagination options for listing members + */ + export interface Pagination { + /** + * Token for the next set of results that was returned as next_token of a + * PaginationResponse + */ + token?: string; + + /** + * Page size is the maximum number of results to retrieve per page. Defaults to 25. + * Maximum 100. + */ + pageSize?: number; + } +} + +export interface OrganizationSetRoleParams { + organizationId: string; + + userId: string; + + role?: Shared.OrganizationRole; +} + +Organizations.DomainVerifications = DomainVerifications; +Organizations.Invites = Invites; +Organizations.Policies = Policies; +Organizations.SSOConfigurations = SSOConfigurations; + +export declare namespace Organizations { + export { + type InviteDomains as InviteDomains, + type Organization as Organization, + type OrganizationMember as OrganizationMember, + type OrganizationTier as OrganizationTier, + type OrganizationCreateResponse as OrganizationCreateResponse, + type OrganizationRetrieveResponse as OrganizationRetrieveResponse, + type OrganizationUpdateResponse as OrganizationUpdateResponse, + type OrganizationDeleteResponse as OrganizationDeleteResponse, + type OrganizationJoinResponse as OrganizationJoinResponse, + type OrganizationLeaveResponse as OrganizationLeaveResponse, + type OrganizationSetRoleResponse as OrganizationSetRoleResponse, + type OrganizationMembersMembersPage as OrganizationMembersMembersPage, + type OrganizationCreateParams as OrganizationCreateParams, + type OrganizationRetrieveParams as OrganizationRetrieveParams, + type OrganizationUpdateParams as OrganizationUpdateParams, + type OrganizationDeleteParams as OrganizationDeleteParams, + type OrganizationJoinParams as OrganizationJoinParams, + type OrganizationLeaveParams as OrganizationLeaveParams, + type OrganizationListMembersParams as OrganizationListMembersParams, + type OrganizationSetRoleParams as OrganizationSetRoleParams, + }; + + export { + DomainVerifications as DomainVerifications, + type DomainVerification as DomainVerification, + type DomainVerificationState as DomainVerificationState, + type DomainVerificationCreateResponse as DomainVerificationCreateResponse, + type DomainVerificationRetrieveResponse as DomainVerificationRetrieveResponse, + type DomainVerificationDeleteResponse as DomainVerificationDeleteResponse, + type DomainVerificationVerifyResponse as DomainVerificationVerifyResponse, + type DomainVerificationsDomainVerificationsPage as DomainVerificationsDomainVerificationsPage, + type DomainVerificationCreateParams as DomainVerificationCreateParams, + type DomainVerificationRetrieveParams as DomainVerificationRetrieveParams, + type DomainVerificationListParams as DomainVerificationListParams, + type DomainVerificationDeleteParams as DomainVerificationDeleteParams, + type DomainVerificationVerifyParams as DomainVerificationVerifyParams, + }; + + export { + Invites as Invites, + type OrganizationInvite as OrganizationInvite, + type InviteCreateResponse as InviteCreateResponse, + type InviteRetrieveResponse as InviteRetrieveResponse, + type InviteGetSummaryResponse as InviteGetSummaryResponse, + type InviteCreateParams as InviteCreateParams, + type InviteRetrieveParams as InviteRetrieveParams, + type InviteGetSummaryParams as InviteGetSummaryParams, + }; + + export { + Policies as Policies, + type OrganizationPolicies as OrganizationPolicies, + type PolicyRetrieveResponse as PolicyRetrieveResponse, + type PolicyUpdateResponse as PolicyUpdateResponse, + type PolicyRetrieveParams as PolicyRetrieveParams, + type PolicyUpdateParams as PolicyUpdateParams, + }; + + export { + SSOConfigurations as SSOConfigurations, + type ProviderType as ProviderType, + type SSOConfiguration as SSOConfiguration, + type SSOConfigurationState as SSOConfigurationState, + type SSOConfigurationCreateResponse as SSOConfigurationCreateResponse, + type SSOConfigurationRetrieveResponse as SSOConfigurationRetrieveResponse, + type SSOConfigurationUpdateResponse as SSOConfigurationUpdateResponse, + type SSOConfigurationDeleteResponse as SSOConfigurationDeleteResponse, + type SSOConfigurationsSSOConfigurationsPage as SSOConfigurationsSSOConfigurationsPage, + type SSOConfigurationCreateParams as SSOConfigurationCreateParams, + type SSOConfigurationRetrieveParams as SSOConfigurationRetrieveParams, + type SSOConfigurationUpdateParams as SSOConfigurationUpdateParams, + type SSOConfigurationListParams as SSOConfigurationListParams, + type SSOConfigurationDeleteParams as SSOConfigurationDeleteParams, + }; +} diff --git a/src/resources/organizations/policies.ts b/src/resources/organizations/policies.ts new file mode 100644 index 0000000..468ef07 --- /dev/null +++ b/src/resources/organizations/policies.ts @@ -0,0 +1,217 @@ +// 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 { RequestOptions } from '../../internal/request-options'; + +export class Policies extends APIResource { + /** + * Gets organization policy settings by organization ID. + * + * Use this method to: + * + * - Retrieve current policy settings for an organization + * - View resource limits and restrictions + * - Check allowed editors and other configurations + * + * ### Examples + * + * - Get organization policies: + * + * Retrieves policy settings for a specific organization. + * + * ```yaml + * organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + * ``` + */ + retrieve(body: PolicyRetrieveParams, options?: RequestOptions): APIPromise<PolicyRetrieveResponse> { + return this._client.post('/gitpod.v1.OrganizationService/GetOrganizationPolicies', { body, ...options }); + } + + /** + * Updates organization policy settings. + * + * Use this method to: + * + * - Configure editor restrictions + * - Set environment resource limits + * - Define project creation permissions + * - Customize default configurations + * + * ### Examples + * + * - Update editor policies: + * + * Restricts available editors and sets a default. + * + * ```yaml + * organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + * allowedEditorIds: + * - "vscode" + * - "jetbrains" + * defaultEditorId: "vscode" + * ``` + * + * - Set environment limits: + * + * Configures limits for environment usage. + * + * ```yaml + * organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + * maximumEnvironmentTimeout: "3600s" + * maximumRunningEnvironmentsPerUser: "5" + * maximumEnvironmentsPerUser: "20" + * ``` + */ + update(body: PolicyUpdateParams, options?: RequestOptions): APIPromise<unknown> { + return this._client.post('/gitpod.v1.OrganizationService/UpdateOrganizationPolicies', { + body, + ...options, + }); + } +} + +export interface OrganizationPolicies { + /** + * allowed_editor_ids is the list of editor IDs that are allowed to be used in the + * organization + */ + allowedEditorIds: Array<string>; + + /** + * allow_local_runners controls whether local runners are allowed to be used in the + * organization + */ + allowLocalRunners: boolean; + + /** + * default_editor_id is the default editor ID to be used when a user doesn't + * specify one + */ + defaultEditorId: string; + + /** + * default_environment_image is the default container image when none is defined in + * repo + */ + defaultEnvironmentImage: string; + + /** + * maximum_environments_per_user limits total environments (running or stopped) per + * user + */ + maximumEnvironmentsPerUser: string; + + /** + * maximum_running_environments_per_user limits simultaneously running environments + * per user + */ + maximumRunningEnvironmentsPerUser: string; + + /** + * members_create_projects controls whether members can create projects + */ + membersCreateProjects: boolean; + + /** + * members_require_projects controls whether environments can only be created from + * projects by non-admin users + */ + membersRequireProjects: boolean; + + /** + * organization_id is the ID of the organization + */ + organizationId: string; + + /** + * maximum_environment_timeout controls the maximum timeout allowed for + * environments in seconds. 0 means no limit (never). Minimum duration is 30 + * minutes. + */ + maximumEnvironmentTimeout?: string; +} + +export interface PolicyRetrieveResponse { + policies: OrganizationPolicies; +} + +export type PolicyUpdateResponse = unknown; + +export interface PolicyRetrieveParams { + /** + * organization_id is the ID of the organization to retrieve policies for + */ + organizationId: string; +} + +export interface PolicyUpdateParams { + /** + * organization_id is the ID of the organization to update policies for + */ + organizationId: string; + + /** + * allowed_editor_ids is the list of editor IDs that are allowed to be used in the + * organization + */ + allowedEditorIds?: Array<string>; + + /** + * allow_local_runners controls whether local runners are allowed to be used in the + * organization + */ + allowLocalRunners?: boolean | null; + + /** + * default_editor_id is the default editor ID to be used when a user doesn't + * specify one + */ + defaultEditorId?: string | null; + + /** + * default_environment_image is the default container image when none is defined in + * repo + */ + defaultEnvironmentImage?: string | null; + + /** + * maximum_environments_per_user limits total environments (running or stopped) per + * user + */ + maximumEnvironmentsPerUser?: string | null; + + /** + * maximum_environment_timeout controls the maximum timeout allowed for + * environments in seconds. 0 means no limit (never). Minimum duration is 30 + * minutes. + */ + maximumEnvironmentTimeout?: string | null; + + /** + * maximum_running_environments_per_user limits simultaneously running environments + * per user + */ + maximumRunningEnvironmentsPerUser?: string | null; + + /** + * members_create_projects controls whether members can create projects + */ + membersCreateProjects?: boolean | null; + + /** + * members_require_projects controls whether environments can only be created from + * projects by non-admin users + */ + membersRequireProjects?: boolean | null; +} + +export declare namespace Policies { + export { + type OrganizationPolicies as OrganizationPolicies, + type PolicyRetrieveResponse as PolicyRetrieveResponse, + type PolicyUpdateResponse as PolicyUpdateResponse, + type PolicyRetrieveParams as PolicyRetrieveParams, + type PolicyUpdateParams as PolicyUpdateParams, + }; +} diff --git a/src/resources/organizations/sso-configurations.ts b/src/resources/organizations/sso-configurations.ts new file mode 100644 index 0000000..a447375 --- /dev/null +++ b/src/resources/organizations/sso-configurations.ts @@ -0,0 +1,360 @@ +// 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, SSOConfigurationsPage, type SSOConfigurationsPageParams } from '../../core/pagination'; +import { RequestOptions } from '../../internal/request-options'; + +export class SSOConfigurations extends APIResource { + /** + * Creates or updates SSO configuration for organizational authentication. + * + * Use this method to: + * + * - Configure OIDC-based SSO providers + * - Set up built-in providers (Google, GitHub, etc.) + * - Define custom identity providers + * - Manage authentication policies + * + * ### Examples + * + * - Configure built-in Google SSO: + * + * Sets up SSO using Google Workspace. + * + * ```yaml + * organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + * clientId: "012345678-abcdefghijklmnopqrstuvwxyz.apps.googleusercontent.com" + * clientSecret: "GOCSPX-abcdefghijklmnopqrstuvwxyz123456" + * issuerUrl: "https://accounts.google.com" + * emailDomain: "acme-corp.com" + * ``` + * + * - Configure custom OIDC provider: + * + * Sets up SSO with a custom identity provider. + * + * ```yaml + * organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + * clientId: "acme-corp-gitpod" + * clientSecret: "secret-token-value" + * issuerUrl: "https://sso.acme-corp.com" + * emailDomain: "acme-corp.com" + * ``` + */ + create( + body: SSOConfigurationCreateParams, + options?: RequestOptions, + ): APIPromise<SSOConfigurationCreateResponse> { + return this._client.post('/gitpod.v1.OrganizationService/CreateSSOConfiguration', { body, ...options }); + } + + /** + * Retrieves a specific SSO configuration. + * + * Use this method to: + * + * - View SSO provider details + * - Check configuration status + * - Verify SSO settings + * + * ### Examples + * + * - Get SSO configuration: + * + * Retrieves details of a specific SSO configuration. + * + * ```yaml + * ssoConfigurationId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + * ``` + */ + retrieve( + body: SSOConfigurationRetrieveParams, + options?: RequestOptions, + ): APIPromise<SSOConfigurationRetrieveResponse> { + return this._client.post('/gitpod.v1.OrganizationService/GetSSOConfiguration', { body, ...options }); + } + + /** + * Updates SSO provider settings and authentication rules. + * + * Use this method to: + * + * - Rotate client credentials + * - Update provider endpoints + * - Modify claim mappings + * - Change authentication policies + * - Toggle SSO enforcement + * + * ### Examples + * + * - Update credentials: + * + * Rotates client ID and secret. + * + * ```yaml + * ssoConfigurationId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + * clientId: "new-client-id" + * clientSecret: "new-client-secret" + * ``` + * + * - Update provider status: + * + * Activates or deactivates SSO provider. + * + * ```yaml + * ssoConfigurationId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + * state: SSO_CONFIGURATION_STATE_ACTIVE + * ``` + */ + update(body: SSOConfigurationUpdateParams, options?: RequestOptions): APIPromise<unknown> { + return this._client.post('/gitpod.v1.OrganizationService/UpdateSSOConfiguration', { body, ...options }); + } + + /** + * Lists and filters SSO configurations for an organization. + * + * Use this method to: + * + * - View all SSO providers + * - Monitor authentication status + * - Audit security settings + * - Manage provider configurations + * + * ### Examples + * + * - List active configurations: + * + * Shows all active SSO providers. + * + * ```yaml + * organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + * pagination: + * pageSize: 20 + * ``` + * + * - List by provider type: + * + * Shows custom SSO configurations. + * + * ```yaml + * organizationId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + * pagination: + * pageSize: 20 + * token: "next-page-token-from-previous-response" + * ``` + */ + list( + params: SSOConfigurationListParams, + options?: RequestOptions, + ): PagePromise<SSOConfigurationsSSOConfigurationsPage, SSOConfiguration> { + const { token, pageSize, ...body } = params; + return this._client.getAPIList( + '/gitpod.v1.OrganizationService/ListSSOConfigurations', + SSOConfigurationsPage<SSOConfiguration>, + { query: { token, pageSize }, body, method: 'post', ...options }, + ); + } + + /** + * Removes an SSO configuration from an organization. + * + * Use this method to: + * + * - Disable SSO authentication + * - Remove outdated providers + * - Clean up unused configurations + * + * ### Examples + * + * - Delete SSO configuration: + * + * Removes a specific SSO configuration. + * + * ```yaml + * ssoConfigurationId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + * ``` + */ + delete(body: SSOConfigurationDeleteParams, options?: RequestOptions): APIPromise<unknown> { + return this._client.post('/gitpod.v1.OrganizationService/DeleteSSOConfiguration', { body, ...options }); + } +} + +export type SSOConfigurationsSSOConfigurationsPage = SSOConfigurationsPage<SSOConfiguration>; + +export type ProviderType = 'PROVIDER_TYPE_UNSPECIFIED' | 'PROVIDER_TYPE_BUILTIN' | 'PROVIDER_TYPE_CUSTOM'; + +export interface SSOConfiguration { + /** + * id is the unique identifier of the SSO configuration + */ + id: string; + + /** + * issuer_url is the URL of the IdP issuer + */ + issuerUrl: string; + + organizationId: string; + + /** + * provider_type defines the type of the SSO configuration + */ + providerType: ProviderType; + + /** + * state is the state of the SSO configuration + */ + state: SSOConfigurationState; + + /** + * claims are key/value pairs that defines a mapping of claims issued by the IdP. + */ + claims?: Record<string, string>; + + /** + * client_id is the client ID of the OIDC application set on the IdP + */ + clientId?: string; + + emailDomain?: string; +} + +export type SSOConfigurationState = + | 'SSO_CONFIGURATION_STATE_UNSPECIFIED' + | 'SSO_CONFIGURATION_STATE_INACTIVE' + | 'SSO_CONFIGURATION_STATE_ACTIVE'; + +export interface SSOConfigurationCreateResponse { + /** + * sso_configuration is the created SSO configuration + */ + ssoConfiguration: SSOConfiguration; +} + +export interface SSOConfigurationRetrieveResponse { + /** + * sso_configuration is the SSO configuration identified by the ID + */ + ssoConfiguration: SSOConfiguration; +} + +export type SSOConfigurationUpdateResponse = unknown; + +export type SSOConfigurationDeleteResponse = unknown; + +export interface SSOConfigurationCreateParams { + /** + * client_id is the client ID of the OIDC application set on the IdP + */ + clientId: string; + + /** + * client_secret is the client secret of the OIDC application set on the IdP + */ + clientSecret: string; + + /** + * email_domain is the domain that is allowed to sign in to the organization + */ + emailDomain: string; + + /** + * issuer_url is the URL of the IdP issuer + */ + issuerUrl: string; + + organizationId: string; +} + +export interface SSOConfigurationRetrieveParams { + /** + * sso_configuration_id is the ID of the SSO configuration to get + */ + ssoConfigurationId: string; +} + +export interface SSOConfigurationUpdateParams { + /** + * sso_configuration_id is the ID of the SSO configuration to update + */ + ssoConfigurationId: string; + + /** + * claims are key/value pairs that defines a mapping of claims issued by the IdP. + */ + claims?: Record<string, string>; + + /** + * client_id is the client ID of the SSO provider + */ + clientId?: string | null; + + /** + * client_secret is the client secret of the SSO provider + */ + clientSecret?: string | null; + + emailDomain?: string | null; + + /** + * issuer_url is the URL of the IdP issuer + */ + issuerUrl?: string | null; + + /** + * state is the state of the SSO configuration + */ + state?: SSOConfigurationState | null; +} + +export interface SSOConfigurationListParams extends SSOConfigurationsPageParams { + /** + * Body param: organization_id is the ID of the organization to list SSO + * configurations for. + */ + organizationId: string; + + /** + * Body param: + */ + pagination?: SSOConfigurationListParams.Pagination; +} + +export namespace SSOConfigurationListParams { + export interface Pagination { + /** + * Token for the next set of results that was returned as next_token of a + * PaginationResponse + */ + token?: string; + + /** + * Page size is the maximum number of results to retrieve per page. Defaults to 25. + * Maximum 100. + */ + pageSize?: number; + } +} + +export interface SSOConfigurationDeleteParams { + ssoConfigurationId: string; +} + +export declare namespace SSOConfigurations { + export { + type ProviderType as ProviderType, + type SSOConfiguration as SSOConfiguration, + type SSOConfigurationState as SSOConfigurationState, + type SSOConfigurationCreateResponse as SSOConfigurationCreateResponse, + type SSOConfigurationRetrieveResponse as SSOConfigurationRetrieveResponse, + type SSOConfigurationUpdateResponse as SSOConfigurationUpdateResponse, + type SSOConfigurationDeleteResponse as SSOConfigurationDeleteResponse, + type SSOConfigurationsSSOConfigurationsPage as SSOConfigurationsSSOConfigurationsPage, + type SSOConfigurationCreateParams as SSOConfigurationCreateParams, + type SSOConfigurationRetrieveParams as SSOConfigurationRetrieveParams, + type SSOConfigurationUpdateParams as SSOConfigurationUpdateParams, + type SSOConfigurationListParams as SSOConfigurationListParams, + type SSOConfigurationDeleteParams as SSOConfigurationDeleteParams, + }; +} diff --git a/src/resources/projects.ts b/src/resources/projects.ts new file mode 100644 index 0000000..f9985fc --- /dev/null +++ b/src/resources/projects.ts @@ -0,0 +1,3 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export * from './projects/index'; diff --git a/src/resources/projects/index.ts b/src/resources/projects/index.ts new file mode 100644 index 0000000..0dc0a82 --- /dev/null +++ b/src/resources/projects/index.ts @@ -0,0 +1,34 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export { + Policies, + type ProjectPolicy, + type ProjectRole, + type PolicyCreateResponse, + type PolicyUpdateResponse, + type PolicyDeleteResponse, + type PolicyCreateParams, + type PolicyUpdateParams, + type PolicyListParams, + type PolicyDeleteParams, + type ProjectPoliciesPoliciesPage, +} from './policies'; +export { + Projects, + type EnvironmentInitializer, + type Project, + type ProjectEnvironmentClass, + type ProjectMetadata, + type ProjectCreateResponse, + type ProjectRetrieveResponse, + type ProjectUpdateResponse, + type ProjectDeleteResponse, + type ProjectCreateFromEnvironmentResponse, + type ProjectCreateParams, + type ProjectRetrieveParams, + type ProjectUpdateParams, + type ProjectListParams, + type ProjectDeleteParams, + type ProjectCreateFromEnvironmentParams, + type ProjectsProjectsPage, +} from './projects'; diff --git a/src/resources/projects/policies.ts b/src/resources/projects/policies.ts new file mode 100644 index 0000000..ea39ec5 --- /dev/null +++ b/src/resources/projects/policies.ts @@ -0,0 +1,229 @@ +// 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, PoliciesPage, type PoliciesPageParams } from '../../core/pagination'; +import { RequestOptions } from '../../internal/request-options'; + +export class Policies extends APIResource { + /** + * Creates a new policy for a project. + * + * Use this method to: + * + * - Set up access controls + * - Define group permissions + * - Configure role-based access + * + * ### Examples + * + * - Create admin policy: + * + * Grants admin access to a group. + * + * ```yaml + * projectId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + * groupId: "f53d2330-3795-4c5d-a1f3-453121af9c60" + * role: PROJECT_ROLE_ADMIN + * ``` + */ + create(body: PolicyCreateParams, options?: RequestOptions): APIPromise<PolicyCreateResponse> { + return this._client.post('/gitpod.v1.ProjectService/CreateProjectPolicy', { body, ...options }); + } + + /** + * Updates an existing project policy. + * + * Use this method to: + * + * - Modify access levels + * - Change group roles + * - Update permissions + * + * ### Examples + * + * - Update policy role: + * + * Changes a group's access level. + * + * ```yaml + * projectId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + * groupId: "f53d2330-3795-4c5d-a1f3-453121af9c60" + * role: PROJECT_ROLE_EDITOR + * ``` + */ + update(body: PolicyUpdateParams, options?: RequestOptions): APIPromise<PolicyUpdateResponse> { + return this._client.post('/gitpod.v1.ProjectService/UpdateProjectPolicy', { body, ...options }); + } + + /** + * Lists policies for a project. + * + * Use this method to: + * + * - View access controls + * - Check policy configurations + * - Audit permissions + * + * ### Examples + * + * - List policies: + * + * Shows all policies for a project. + * + * ```yaml + * projectId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + * pagination: + * pageSize: 20 + * ``` + */ + list( + params: PolicyListParams, + options?: RequestOptions, + ): PagePromise<ProjectPoliciesPoliciesPage, ProjectPolicy> { + const { token, pageSize, ...body } = params; + return this._client.getAPIList( + '/gitpod.v1.ProjectService/ListProjectPolicies', + PoliciesPage<ProjectPolicy>, + { query: { token, pageSize }, body, method: 'post', ...options }, + ); + } + + /** + * Deletes a project policy. + * + * Use this method to: + * + * - Remove access controls + * - Revoke permissions + * - Clean up policies + * + * ### Examples + * + * - Delete policy: + * + * Removes a group's access policy. + * + * ```yaml + * projectId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + * groupId: "f53d2330-3795-4c5d-a1f3-453121af9c60" + * ``` + */ + delete(body: PolicyDeleteParams, options?: RequestOptions): APIPromise<unknown> { + return this._client.post('/gitpod.v1.ProjectService/DeleteProjectPolicy', { body, ...options }); + } +} + +export type ProjectPoliciesPoliciesPage = PoliciesPage<ProjectPolicy>; + +export interface ProjectPolicy { + groupId?: string; + + /** + * role is the role assigned to the group + */ + role?: ProjectRole; +} + +export type ProjectRole = + | 'PROJECT_ROLE_UNSPECIFIED' + | 'PROJECT_ROLE_ADMIN' + | 'PROJECT_ROLE_USER' + | 'PROJECT_ROLE_EDITOR'; + +export interface PolicyCreateResponse { + policy?: ProjectPolicy; +} + +export interface PolicyUpdateResponse { + policy?: ProjectPolicy; +} + +export type PolicyDeleteResponse = unknown; + +export interface PolicyCreateParams { + /** + * group_id specifies the group_id identifier + */ + groupId?: string; + + /** + * project_id specifies the project identifier + */ + projectId?: string; + + role?: ProjectRole; +} + +export interface PolicyUpdateParams { + /** + * group_id specifies the group_id identifier + */ + groupId?: string; + + /** + * project_id specifies the project identifier + */ + projectId?: string; + + role?: ProjectRole; +} + +export interface PolicyListParams extends PoliciesPageParams { + /** + * Body param: pagination contains the pagination options for listing project + * policies + */ + pagination?: PolicyListParams.Pagination; + + /** + * Body param: project_id specifies the project identifier + */ + projectId?: string; +} + +export namespace PolicyListParams { + /** + * pagination contains the pagination options for listing project policies + */ + export interface Pagination { + /** + * Token for the next set of results that was returned as next_token of a + * PaginationResponse + */ + token?: string; + + /** + * Page size is the maximum number of results to retrieve per page. Defaults to 25. + * Maximum 100. + */ + pageSize?: number; + } +} + +export interface PolicyDeleteParams { + /** + * group_id specifies the group_id identifier + */ + groupId?: string; + + /** + * project_id specifies the project identifier + */ + projectId?: string; +} + +export declare namespace Policies { + export { + type ProjectPolicy as ProjectPolicy, + type ProjectRole as ProjectRole, + type PolicyCreateResponse as PolicyCreateResponse, + type PolicyUpdateResponse as PolicyUpdateResponse, + type PolicyDeleteResponse as PolicyDeleteResponse, + type ProjectPoliciesPoliciesPage as ProjectPoliciesPoliciesPage, + type PolicyCreateParams as PolicyCreateParams, + type PolicyUpdateParams as PolicyUpdateParams, + type PolicyListParams as PolicyListParams, + type PolicyDeleteParams as PolicyDeleteParams, + }; +} diff --git a/src/resources/projects/projects.ts b/src/resources/projects/projects.ts new file mode 100644 index 0000000..27f10b3 --- /dev/null +++ b/src/resources/projects/projects.ts @@ -0,0 +1,727 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../../core/resource'; +import * as Shared from '../shared'; +import * as PoliciesAPI from './policies'; +import { + Policies, + PolicyCreateParams, + PolicyCreateResponse, + PolicyDeleteParams, + PolicyDeleteResponse, + PolicyListParams, + PolicyUpdateParams, + PolicyUpdateResponse, + ProjectPoliciesPoliciesPage, + ProjectPolicy, + ProjectRole, +} from './policies'; +import { APIPromise } from '../../core/api-promise'; +import { PagePromise, ProjectsPage, type ProjectsPageParams } from '../../core/pagination'; +import { RequestOptions } from '../../internal/request-options'; + +export class Projects extends APIResource { + policies: PoliciesAPI.Policies = new PoliciesAPI.Policies(this._client); + + /** + * Creates a new project with specified configuration. + * + * Use this method to: + * + * - Set up development projects + * - Configure project environments + * - Define project settings + * - Initialize project content + * + * ### Examples + * + * - Create basic project: + * + * Creates a project with minimal configuration. + * + * ```yaml + * name: "Web Application" + * environmentClass: + * environmentClassId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + * initializer: + * specs: + * - git: + * remoteUri: "https://github.com/org/repo" + * ``` + * + * - Create project with devcontainer: + * + * Creates a project with custom development container. + * + * ```yaml + * name: "Backend Service" + * environmentClass: + * environmentClassId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + * initializer: + * specs: + * - git: + * remoteUri: "https://github.com/org/backend" + * devcontainerFilePath: ".devcontainer/devcontainer.json" + * automationsFilePath: ".gitpod/automations.yaml" + * ``` + */ + create(body: ProjectCreateParams, options?: RequestOptions): APIPromise<ProjectCreateResponse> { + return this._client.post('/gitpod.v1.ProjectService/CreateProject', { body, ...options }); + } + + /** + * Gets details about a specific project. + * + * Use this method to: + * + * - View project configuration + * - Check project status + * - Get project metadata + * + * ### Examples + * + * - Get project details: + * + * Retrieves information about a specific project. + * + * ```yaml + * projectId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + * ``` + */ + retrieve(body: ProjectRetrieveParams, options?: RequestOptions): APIPromise<ProjectRetrieveResponse> { + return this._client.post('/gitpod.v1.ProjectService/GetProject', { body, ...options }); + } + + /** + * Updates a project's configuration. + * + * Use this method to: + * + * - Modify project settings + * - Update environment class + * - Change project name + * - Configure initializers + * + * ### Examples + * + * - Update project name: + * + * Changes the project's display name. + * + * ```yaml + * projectId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + * name: "New Project Name" + * ``` + * + * - Update environment class: + * + * Changes the project's environment class. + * + * ```yaml + * projectId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + * environmentClass: + * environmentClassId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + * ``` + */ + update(body: ProjectUpdateParams, options?: RequestOptions): APIPromise<ProjectUpdateResponse> { + return this._client.post('/gitpod.v1.ProjectService/UpdateProject', { body, ...options }); + } + + /** + * Lists projects with optional filtering. + * + * Use this method to: + * + * - View all accessible projects + * - Browse project configurations + * - Monitor project status + * + * ### Examples + * + * - List projects: + * + * Shows all projects with pagination. + * + * ```yaml + * pagination: + * pageSize: 20 + * ``` + */ + list(params: ProjectListParams, options?: RequestOptions): PagePromise<ProjectsProjectsPage, Project> { + const { token, pageSize, ...body } = params; + return this._client.getAPIList('/gitpod.v1.ProjectService/ListProjects', ProjectsPage<Project>, { + query: { token, pageSize }, + body, + method: 'post', + ...options, + }); + } + + /** + * Deletes a project permanently. + * + * Use this method to: + * + * - Remove unused projects + * - Clean up test projects + * - Delete obsolete configurations + * + * ### Examples + * + * - Delete project: + * + * Permanently removes a project. + * + * ```yaml + * projectId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + * ``` + */ + delete(body: ProjectDeleteParams, options?: RequestOptions): APIPromise<unknown> { + return this._client.post('/gitpod.v1.ProjectService/DeleteProject', { body, ...options }); + } + + /** + * Creates a new project using an existing environment as a template. + * + * Use this method to: + * + * - Clone environment configurations + * - Create projects from templates + * - Share environment setups + * + * ### Examples + * + * - Create from environment: + * + * Creates a project based on existing environment. + * + * ```yaml + * name: "Frontend Project" + * environmentId: "07e03a28-65a5-4d98-b532-8ea67b188048" + * ``` + */ + createFromEnvironment( + body: ProjectCreateFromEnvironmentParams, + options?: RequestOptions, + ): APIPromise<ProjectCreateFromEnvironmentResponse> { + return this._client.post('/gitpod.v1.ProjectService/CreateProjectFromEnvironment', { body, ...options }); + } +} + +export type ProjectsProjectsPage = ProjectsPage<Project>; + +/** + * EnvironmentInitializer specifies how an environment is to be initialized + */ +export interface EnvironmentInitializer { + specs?: Array<EnvironmentInitializer.Spec>; +} + +export namespace EnvironmentInitializer { + export interface Spec { + contextUrl?: Spec.ContextURL; + + git?: Spec.Git; + } + + export namespace Spec { + export interface ContextURL { + /** + * url is the URL from which the environment is created + */ + url?: string; + } + + export interface Git { + /** + * a path relative to the environment root in which the code will be checked out to + */ + checkoutLocation?: string; + + /** + * the value for the clone target mode - use depends on the target mode + */ + cloneTarget?: string; + + /** + * remote_uri is the Git remote origin + */ + remoteUri?: string; + + /** + * the target mode determines what gets checked out + */ + targetMode?: + | 'CLONE_TARGET_MODE_UNSPECIFIED' + | 'CLONE_TARGET_MODE_REMOTE_HEAD' + | 'CLONE_TARGET_MODE_REMOTE_COMMIT' + | 'CLONE_TARGET_MODE_REMOTE_BRANCH' + | 'CLONE_TARGET_MODE_LOCAL_BRANCH'; + + /** + * upstream_Remote_uri is the fork upstream of a repository + */ + upstreamRemoteUri?: string; + } + } +} + +export interface Project { + environmentClass: ProjectEnvironmentClass; + + /** + * id is the unique identifier for the project + */ + id?: string; + + /** + * automations_file_path is the path to the automations file relative to the repo + * root + */ + automationsFilePath?: string; + + /** + * devcontainer_file_path is the path to the devcontainer file relative to the repo + * root + */ + devcontainerFilePath?: string; + + /** + * initializer is the content initializer + */ + initializer?: EnvironmentInitializer; + + metadata?: ProjectMetadata; + + /** + * technical_description is a detailed technical description of the project This + * field is not returned by default in GetProject or ListProjects responses + */ + technicalDescription?: string; + + usedBy?: Project.UsedBy; +} + +export namespace Project { + export interface UsedBy { + /** + * Subjects are the 10 most recent subjects who have used the project to create an + * environment + */ + subjects?: Array<Shared.Subject>; + + /** + * Total number of unique subjects who have used the project + */ + totalSubjects?: number; + } +} + +export interface ProjectEnvironmentClass { + /** + * Use a fixed environment class on a given Runner. This cannot be a local runner's + * environment class. + */ + environmentClassId?: string; + + /** + * Use a local runner for the user + */ + localRunner?: boolean; +} + +export interface ProjectMetadata { + /** + * A Timestamp represents a point in time independent of any time zone or local + * calendar, encoded as a count of seconds and fractions of seconds at nanosecond + * resolution. The count is relative to an epoch at UTC midnight on January 1, + * 1970, in the proleptic Gregorian calendar which extends the Gregorian calendar + * backwards to year one. + * + * All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap + * second table is needed for interpretation, using a + * [24-hour linear smear](https://developers.google.com/time/smear). + * + * The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By + * restricting to that range, we ensure that we can convert to and from + * [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. + * + * # Examples + * + * Example 1: Compute Timestamp from POSIX `time()`. + * + * Timestamp timestamp; + * timestamp.set_seconds(time(NULL)); + * timestamp.set_nanos(0); + * + * Example 2: Compute Timestamp from POSIX `gettimeofday()`. + * + * struct timeval tv; + * gettimeofday(&tv, NULL); + * + * Timestamp timestamp; + * timestamp.set_seconds(tv.tv_sec); + * timestamp.set_nanos(tv.tv_usec * 1000); + * + * Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. + * + * FILETIME ft; + * GetSystemTimeAsFileTime(&ft); + * UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; + * + * // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z + * // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. + * Timestamp timestamp; + * timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); + * timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); + * + * Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. + * + * long millis = System.currentTimeMillis(); + * + * Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) + * .setNanos((int) ((millis % 1000) * 1000000)).build(); + * + * Example 5: Compute Timestamp from Java `Instant.now()`. + * + * Instant now = Instant.now(); + * + * Timestamp timestamp = + * Timestamp.newBuilder().setSeconds(now.getEpochSecond()) + * .setNanos(now.getNano()).build(); + * + * Example 6: Compute Timestamp from current time in Python. + * + * timestamp = Timestamp() + * timestamp.GetCurrentTime() + * + * # JSON Mapping + * + * In JSON format, the Timestamp type is encoded as a string in the + * [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the format is + * "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" where {year} is always + * expressed using four digits while {month}, {day}, {hour}, {min}, and {sec} are + * zero-padded to two digits each. The fractional seconds, which can go up to 9 + * digits (i.e. up to 1 nanosecond resolution), are optional. The "Z" suffix + * indicates the timezone ("UTC"); the timezone is required. A proto3 JSON + * serializer should always use UTC (as indicated by "Z") when printing the + * Timestamp type and a proto3 JSON parser should be able to accept both UTC and + * other timezones (as indicated by an offset). + * + * For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past 01:30 UTC on + * January 15, 2017. + * + * In JavaScript, one can convert a Date object to this format using the standard + * [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) + * method. In Python, a standard `datetime.datetime` object can be converted to + * this format using + * [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with the + * time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use the + * Joda Time's + * [`ISODateTimeFormat.dateTime()`](<http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime()>) + * to obtain a formatter capable of generating timestamps in this format. + */ + createdAt?: string; + + /** + * creator is the identity of the project creator + */ + creator?: Shared.Subject; + + /** + * name is the human readable name of the project + */ + name?: string; + + /** + * organization_id is the ID of the organization that contains the environment + */ + organizationId?: string; + + /** + * A Timestamp represents a point in time independent of any time zone or local + * calendar, encoded as a count of seconds and fractions of seconds at nanosecond + * resolution. The count is relative to an epoch at UTC midnight on January 1, + * 1970, in the proleptic Gregorian calendar which extends the Gregorian calendar + * backwards to year one. + * + * All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap + * second table is needed for interpretation, using a + * [24-hour linear smear](https://developers.google.com/time/smear). + * + * The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By + * restricting to that range, we ensure that we can convert to and from + * [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. + * + * # Examples + * + * Example 1: Compute Timestamp from POSIX `time()`. + * + * Timestamp timestamp; + * timestamp.set_seconds(time(NULL)); + * timestamp.set_nanos(0); + * + * Example 2: Compute Timestamp from POSIX `gettimeofday()`. + * + * struct timeval tv; + * gettimeofday(&tv, NULL); + * + * Timestamp timestamp; + * timestamp.set_seconds(tv.tv_sec); + * timestamp.set_nanos(tv.tv_usec * 1000); + * + * Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. + * + * FILETIME ft; + * GetSystemTimeAsFileTime(&ft); + * UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; + * + * // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z + * // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. + * Timestamp timestamp; + * timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); + * timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); + * + * Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. + * + * long millis = System.currentTimeMillis(); + * + * Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) + * .setNanos((int) ((millis % 1000) * 1000000)).build(); + * + * Example 5: Compute Timestamp from Java `Instant.now()`. + * + * Instant now = Instant.now(); + * + * Timestamp timestamp = + * Timestamp.newBuilder().setSeconds(now.getEpochSecond()) + * .setNanos(now.getNano()).build(); + * + * Example 6: Compute Timestamp from current time in Python. + * + * timestamp = Timestamp() + * timestamp.GetCurrentTime() + * + * # JSON Mapping + * + * In JSON format, the Timestamp type is encoded as a string in the + * [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the format is + * "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" where {year} is always + * expressed using four digits while {month}, {day}, {hour}, {min}, and {sec} are + * zero-padded to two digits each. The fractional seconds, which can go up to 9 + * digits (i.e. up to 1 nanosecond resolution), are optional. The "Z" suffix + * indicates the timezone ("UTC"); the timezone is required. A proto3 JSON + * serializer should always use UTC (as indicated by "Z") when printing the + * Timestamp type and a proto3 JSON parser should be able to accept both UTC and + * other timezones (as indicated by an offset). + * + * For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past 01:30 UTC on + * January 15, 2017. + * + * In JavaScript, one can convert a Date object to this format using the standard + * [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) + * method. In Python, a standard `datetime.datetime` object can be converted to + * this format using + * [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with the + * time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use the + * Joda Time's + * [`ISODateTimeFormat.dateTime()`](<http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime()>) + * to obtain a formatter capable of generating timestamps in this format. + */ + updatedAt?: string; +} + +export interface ProjectCreateResponse { + project?: Project; +} + +export interface ProjectRetrieveResponse { + project?: Project; +} + +export interface ProjectUpdateResponse { + project?: Project; +} + +export type ProjectDeleteResponse = unknown; + +export interface ProjectCreateFromEnvironmentResponse { + project?: Project; +} + +export interface ProjectCreateParams { + environmentClass: ProjectEnvironmentClass; + + /** + * initializer is the content initializer + */ + initializer: EnvironmentInitializer; + + /** + * automations_file_path is the path to the automations file relative to the repo + * root path must not be absolute (start with a /): + * + * ``` + * this.matches('^$|^[^/].*') + * ``` + */ + automationsFilePath?: string; + + /** + * devcontainer_file_path is the path to the devcontainer file relative to the repo + * root path must not be absolute (start with a /): + * + * ``` + * this.matches('^$|^[^/].*') + * ``` + */ + devcontainerFilePath?: string; + + name?: string; + + /** + * technical_description is a detailed technical description of the project This + * field is not returned by default in GetProject or ListProjects responses 8KB max + */ + technicalDescription?: string; +} + +export interface ProjectRetrieveParams { + /** + * project_id specifies the project identifier + */ + projectId?: string; +} + +export interface ProjectUpdateParams { + /** + * automations_file_path is the path to the automations file relative to the repo + * root path must not be absolute (start with a /): + * + * ``` + * this.matches('^$|^[^/].*') + * ``` + */ + automationsFilePath?: string | null; + + /** + * devcontainer_file_path is the path to the devcontainer file relative to the repo + * root path must not be absolute (start with a /): + * + * ``` + * this.matches('^$|^[^/].*') + * ``` + */ + devcontainerFilePath?: string | null; + + environmentClass?: ProjectEnvironmentClass | null; + + /** + * initializer is the content initializer + */ + initializer?: EnvironmentInitializer | null; + + name?: string | null; + + /** + * project_id specifies the project identifier + */ + projectId?: string; + + /** + * technical_description is a detailed technical description of the project This + * field is not returned by default in GetProject or ListProjects responses 8KB max + */ + technicalDescription?: string | null; +} + +export interface ProjectListParams extends ProjectsPageParams { + /** + * Body param: + */ + filter?: ProjectListParams.Filter; + + /** + * Body param: pagination contains the pagination options for listing organizations + */ + pagination?: ProjectListParams.Pagination; +} + +export namespace ProjectListParams { + export interface Filter { + /** + * project_ids filters the response to only projects with these IDs + */ + projectIds?: Array<string>; + } + + /** + * pagination contains the pagination options for listing organizations + */ + export interface Pagination { + /** + * Token for the next set of results that was returned as next_token of a + * PaginationResponse + */ + token?: string; + + /** + * Page size is the maximum number of results to retrieve per page. Defaults to 25. + * Maximum 100. + */ + pageSize?: number; + } +} + +export interface ProjectDeleteParams { + /** + * project_id specifies the project identifier + */ + projectId?: string; +} + +export interface ProjectCreateFromEnvironmentParams { + /** + * environment_id specifies the environment identifier + */ + environmentId?: string; + + name?: string; +} + +Projects.Policies = Policies; + +export declare namespace Projects { + export { + type EnvironmentInitializer as EnvironmentInitializer, + type Project as Project, + type ProjectEnvironmentClass as ProjectEnvironmentClass, + type ProjectMetadata as ProjectMetadata, + type ProjectCreateResponse as ProjectCreateResponse, + type ProjectRetrieveResponse as ProjectRetrieveResponse, + type ProjectUpdateResponse as ProjectUpdateResponse, + type ProjectDeleteResponse as ProjectDeleteResponse, + type ProjectCreateFromEnvironmentResponse as ProjectCreateFromEnvironmentResponse, + type ProjectsProjectsPage as ProjectsProjectsPage, + type ProjectCreateParams as ProjectCreateParams, + type ProjectRetrieveParams as ProjectRetrieveParams, + type ProjectUpdateParams as ProjectUpdateParams, + type ProjectListParams as ProjectListParams, + type ProjectDeleteParams as ProjectDeleteParams, + type ProjectCreateFromEnvironmentParams as ProjectCreateFromEnvironmentParams, + }; + + export { + Policies as Policies, + type ProjectPolicy as ProjectPolicy, + type ProjectRole as ProjectRole, + type PolicyCreateResponse as PolicyCreateResponse, + type PolicyUpdateResponse as PolicyUpdateResponse, + type PolicyDeleteResponse as PolicyDeleteResponse, + type ProjectPoliciesPoliciesPage as ProjectPoliciesPoliciesPage, + type PolicyCreateParams as PolicyCreateParams, + type PolicyUpdateParams as PolicyUpdateParams, + type PolicyListParams as PolicyListParams, + type PolicyDeleteParams as PolicyDeleteParams, + }; +} diff --git a/src/resources/runners.ts b/src/resources/runners.ts new file mode 100644 index 0000000..003f18c --- /dev/null +++ b/src/resources/runners.ts @@ -0,0 +1,3 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export * from './runners/index'; diff --git a/src/resources/runners/configurations.ts b/src/resources/runners/configurations.ts new file mode 100644 index 0000000..451b34e --- /dev/null +++ b/src/resources/runners/configurations.ts @@ -0,0 +1,3 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export * from './configurations/index'; diff --git a/src/resources/runners/configurations/configurations.ts b/src/resources/runners/configurations/configurations.ts new file mode 100644 index 0000000..db30ece --- /dev/null +++ b/src/resources/runners/configurations/configurations.ts @@ -0,0 +1,243 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../../../core/resource'; +import * as Shared from '../../shared'; +import * as EnvironmentClassesAPI from './environment-classes'; +import { + EnvironmentClassCreateParams, + EnvironmentClassCreateResponse, + EnvironmentClassListParams, + EnvironmentClassRetrieveParams, + EnvironmentClassRetrieveResponse, + EnvironmentClassUpdateParams, + EnvironmentClassUpdateResponse, + EnvironmentClasses, +} from './environment-classes'; +import * as HostAuthenticationTokensAPI from './host-authentication-tokens'; +import { + HostAuthenticationToken, + HostAuthenticationTokenCreateParams, + HostAuthenticationTokenCreateResponse, + HostAuthenticationTokenDeleteParams, + HostAuthenticationTokenDeleteResponse, + HostAuthenticationTokenListParams, + HostAuthenticationTokenRetrieveParams, + HostAuthenticationTokenRetrieveResponse, + HostAuthenticationTokenSource, + HostAuthenticationTokenUpdateParams, + HostAuthenticationTokenUpdateResponse, + HostAuthenticationTokens, + HostAuthenticationTokensTokensPage, +} from './host-authentication-tokens'; +import * as SchemaAPI from './schema'; +import { RunnerConfigurationSchema, Schema, SchemaRetrieveParams, SchemaRetrieveResponse } from './schema'; +import * as ScmIntegrationsAPI from './scm-integrations'; +import { + ScmIntegration as ScmIntegrationsAPIScmIntegration, + ScmIntegrationCreateParams, + ScmIntegrationCreateResponse, + ScmIntegrationDeleteParams, + ScmIntegrationDeleteResponse, + ScmIntegrationListParams, + ScmIntegrationOAuthConfig, + ScmIntegrationRetrieveParams, + ScmIntegrationRetrieveResponse, + ScmIntegrationUpdateParams, + ScmIntegrationUpdateResponse, + ScmIntegrations, + ScmIntegrationsIntegrationsPage, +} from './scm-integrations'; +import { APIPromise } from '../../../core/api-promise'; +import { RequestOptions } from '../../../internal/request-options'; + +export class Configurations extends APIResource { + environmentClasses: EnvironmentClassesAPI.EnvironmentClasses = new EnvironmentClassesAPI.EnvironmentClasses( + this._client, + ); + hostAuthenticationTokens: HostAuthenticationTokensAPI.HostAuthenticationTokens = + new HostAuthenticationTokensAPI.HostAuthenticationTokens(this._client); + schema: SchemaAPI.Schema = new SchemaAPI.Schema(this._client); + scmIntegrations: ScmIntegrationsAPI.ScmIntegrations = new ScmIntegrationsAPI.ScmIntegrations(this._client); + + /** + * Validates a runner configuration. + * + * Use this method to: + * + * - Check configuration validity + * - Verify integration settings + * - Validate environment classes + * + * ### Examples + * + * - Validate SCM integration: + * + * Checks if an SCM integration is valid. + * + * ```yaml + * runnerId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + * scmIntegration: + * id: "integration-id" + * scmId: "github" + * host: "github.com" + * oauthClientId: "client_id" + * oauthPlaintextClientSecret: "client_secret" + * ``` + */ + validate( + body: ConfigurationValidateParams, + options?: RequestOptions, + ): APIPromise<ConfigurationValidateResponse> { + return this._client.post('/gitpod.v1.RunnerConfigurationService/ValidateRunnerConfiguration', { + body, + ...options, + }); + } +} + +export interface EnvironmentClassValidationResult { + configurationErrors?: Array<FieldValidationError>; + + descriptionError?: string | null; + + displayNameError?: string | null; + + valid?: boolean; +} + +export interface FieldValidationError { + error?: string; + + key?: string; +} + +export interface ScmIntegrationValidationResult { + hostError?: string | null; + + oauthError?: string | null; + + patError?: string | null; + + scmIdError?: string | null; + + valid?: boolean; +} + +export interface ConfigurationValidateResponse { + environmentClass?: EnvironmentClassValidationResult; + + scmIntegration?: ScmIntegrationValidationResult; +} + +export interface ConfigurationValidateParams { + environmentClass?: Shared.EnvironmentClass; + + runnerId?: string; + + scmIntegration?: ConfigurationValidateParams.ScmIntegration; +} + +export namespace ConfigurationValidateParams { + export interface ScmIntegration { + /** + * id is the unique identifier of the SCM integration + */ + id?: string; + + host?: string; + + /** + * oauth_client_id is the OAuth app's client ID, if OAuth is configured. If + * configured, oauth_client_secret must also be set. + */ + oauthClientId?: string | null; + + /** + * oauth_encrypted_client_secret is the OAuth app's client secret encrypted with + * the runner's public key, if OAuth is configured. This can be used to e.g. + * validate an already encrypted client secret of an existing SCM integration. + */ + oauthEncryptedClientSecret?: string; + + /** + * oauth_plaintext_client_secret is the OAuth app's client secret in clear text, if + * OAuth is configured. This can be set to validate any new client secret before it + * is encrypted and stored. This value will not be stored and get encrypted with + * the runner's public key before passing it to the runner. + */ + oauthPlaintextClientSecret?: string; + + pat?: boolean; + + /** + * scm_id references the scm_id in the runner's configuration schema that this + * integration is for + */ + scmId?: string; + } +} + +Configurations.EnvironmentClasses = EnvironmentClasses; +Configurations.HostAuthenticationTokens = HostAuthenticationTokens; +Configurations.Schema = Schema; +Configurations.ScmIntegrations = ScmIntegrations; + +export declare namespace Configurations { + export { + type EnvironmentClassValidationResult as EnvironmentClassValidationResult, + type FieldValidationError as FieldValidationError, + type ScmIntegrationValidationResult as ScmIntegrationValidationResult, + type ConfigurationValidateResponse as ConfigurationValidateResponse, + type ConfigurationValidateParams as ConfigurationValidateParams, + }; + + export { + EnvironmentClasses as EnvironmentClasses, + type EnvironmentClassCreateResponse as EnvironmentClassCreateResponse, + type EnvironmentClassRetrieveResponse as EnvironmentClassRetrieveResponse, + type EnvironmentClassUpdateResponse as EnvironmentClassUpdateResponse, + type EnvironmentClassCreateParams as EnvironmentClassCreateParams, + type EnvironmentClassRetrieveParams as EnvironmentClassRetrieveParams, + type EnvironmentClassUpdateParams as EnvironmentClassUpdateParams, + type EnvironmentClassListParams as EnvironmentClassListParams, + }; + + export { + HostAuthenticationTokens as HostAuthenticationTokens, + type HostAuthenticationToken as HostAuthenticationToken, + type HostAuthenticationTokenSource as HostAuthenticationTokenSource, + type HostAuthenticationTokenCreateResponse as HostAuthenticationTokenCreateResponse, + type HostAuthenticationTokenRetrieveResponse as HostAuthenticationTokenRetrieveResponse, + type HostAuthenticationTokenUpdateResponse as HostAuthenticationTokenUpdateResponse, + type HostAuthenticationTokenDeleteResponse as HostAuthenticationTokenDeleteResponse, + type HostAuthenticationTokensTokensPage as HostAuthenticationTokensTokensPage, + type HostAuthenticationTokenCreateParams as HostAuthenticationTokenCreateParams, + type HostAuthenticationTokenRetrieveParams as HostAuthenticationTokenRetrieveParams, + type HostAuthenticationTokenUpdateParams as HostAuthenticationTokenUpdateParams, + type HostAuthenticationTokenListParams as HostAuthenticationTokenListParams, + type HostAuthenticationTokenDeleteParams as HostAuthenticationTokenDeleteParams, + }; + + export { + Schema as Schema, + type RunnerConfigurationSchema as RunnerConfigurationSchema, + type SchemaRetrieveResponse as SchemaRetrieveResponse, + type SchemaRetrieveParams as SchemaRetrieveParams, + }; + + export { + ScmIntegrations as ScmIntegrations, + type ScmIntegrationsAPIScmIntegration as ScmIntegration, + type ScmIntegrationOAuthConfig as ScmIntegrationOAuthConfig, + type ScmIntegrationCreateResponse as ScmIntegrationCreateResponse, + type ScmIntegrationRetrieveResponse as ScmIntegrationRetrieveResponse, + type ScmIntegrationUpdateResponse as ScmIntegrationUpdateResponse, + type ScmIntegrationDeleteResponse as ScmIntegrationDeleteResponse, + type ScmIntegrationsIntegrationsPage as ScmIntegrationsIntegrationsPage, + type ScmIntegrationCreateParams as ScmIntegrationCreateParams, + type ScmIntegrationRetrieveParams as ScmIntegrationRetrieveParams, + type ScmIntegrationUpdateParams as ScmIntegrationUpdateParams, + type ScmIntegrationListParams as ScmIntegrationListParams, + type ScmIntegrationDeleteParams as ScmIntegrationDeleteParams, + }; +} diff --git a/src/resources/runners/configurations/environment-classes.ts b/src/resources/runners/configurations/environment-classes.ts new file mode 100644 index 0000000..1db7137 --- /dev/null +++ b/src/resources/runners/configurations/environment-classes.ts @@ -0,0 +1,267 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../../../core/resource'; +import * as Shared from '../../shared'; +import { EnvironmentClassesEnvironmentClassesPage } from '../../shared'; +import * as RunnersAPI from '../runners'; +import { APIPromise } from '../../../core/api-promise'; +import { + EnvironmentClassesPage, + type EnvironmentClassesPageParams, + PagePromise, +} from '../../../core/pagination'; +import { RequestOptions } from '../../../internal/request-options'; + +export class EnvironmentClasses extends APIResource { + /** + * Creates a new environment class for a runner. + * + * Use this method to: + * + * - Define compute resources + * - Configure environment settings + * - Set up runtime options + * + * ### Examples + * + * - Create environment class: + * + * Creates a new environment configuration. + * + * ```yaml + * runnerId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + * displayName: "Large Instance" + * description: "8 CPU, 16GB RAM" + * configuration: + * - key: "cpu" + * value: "8" + * - key: "memory" + * value: "16384" + * ``` + */ + create( + body: EnvironmentClassCreateParams, + options?: RequestOptions, + ): APIPromise<EnvironmentClassCreateResponse> { + return this._client.post('/gitpod.v1.RunnerConfigurationService/CreateEnvironmentClass', { + body, + ...options, + }); + } + + /** + * Gets details about a specific environment class. + * + * Use this method to: + * + * - View class configuration + * - Check resource settings + * - Verify availability + * + * ### Examples + * + * - Get class details: + * + * Retrieves information about a specific class. + * + * ```yaml + * environmentClassId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + * ``` + */ + retrieve( + body: EnvironmentClassRetrieveParams, + options?: RequestOptions, + ): APIPromise<EnvironmentClassRetrieveResponse> { + return this._client.post('/gitpod.v1.RunnerConfigurationService/GetEnvironmentClass', { + body, + ...options, + }); + } + + /** + * Updates an environment class. + * + * Use this method to: + * + * - Modify class settings + * - Update resource limits + * - Change availability + * + * ### Examples + * + * - Update class: + * + * Changes class configuration. + * + * ```yaml + * environmentClassId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + * displayName: "Updated Large Instance" + * description: "16 CPU, 32GB RAM" + * enabled: true + * ``` + */ + update(body: EnvironmentClassUpdateParams, options?: RequestOptions): APIPromise<unknown> { + return this._client.post('/gitpod.v1.RunnerConfigurationService/UpdateEnvironmentClass', { + body, + ...options, + }); + } + + /** + * Lists environment classes with optional filtering. + * + * Use this method to: + * + * - View available classes + * - Filter by capability + * - Check enabled status + * + * ### Examples + * + * - List all classes: + * + * Shows all environment classes. + * + * ```yaml + * pagination: + * pageSize: 20 + * ``` + * + * - Filter enabled classes: + * + * Lists only enabled environment classes. + * + * ```yaml + * filter: + * enabled: true + * pagination: + * pageSize: 20 + * ``` + * + * buf:lint:ignore RPC_REQUEST_RESPONSE_UNIQUE + */ + list( + params: EnvironmentClassListParams, + options?: RequestOptions, + ): PagePromise<EnvironmentClassesEnvironmentClassesPage, Shared.EnvironmentClass> { + const { token, pageSize, ...body } = params; + return this._client.getAPIList( + '/gitpod.v1.RunnerConfigurationService/ListEnvironmentClasses', + EnvironmentClassesPage<Shared.EnvironmentClass>, + { query: { token, pageSize }, body, method: 'post', ...options }, + ); + } +} + +export interface EnvironmentClassCreateResponse { + id?: string; +} + +export interface EnvironmentClassRetrieveResponse { + environmentClass?: Shared.EnvironmentClass; +} + +export type EnvironmentClassUpdateResponse = unknown; + +export interface EnvironmentClassCreateParams { + configuration?: Array<Shared.FieldValue>; + + description?: string; + + displayName?: string; + + runnerId?: string; +} + +export interface EnvironmentClassRetrieveParams { + environmentClassId?: string; +} + +export interface EnvironmentClassUpdateParams { + description?: string | null; + + displayName?: string | null; + + enabled?: boolean | null; + + environmentClassId?: string; +} + +export interface EnvironmentClassListParams extends EnvironmentClassesPageParams { + /** + * Body param: + */ + filter?: EnvironmentClassListParams.Filter; + + /** + * Body param: pagination contains the pagination options for listing environment + * classes + */ + pagination?: EnvironmentClassListParams.Pagination; +} + +export namespace EnvironmentClassListParams { + export interface Filter { + /** + * can_create_environments filters the response to only environment classes that + * can be used to create new environments by the caller. Unlike enabled, which + * indicates general availability, this ensures the caller only sees environment + * classes they are allowed to use. + */ + canCreateEnvironments?: boolean | null; + + /** + * enabled filters the response to only enabled or disabled environment classes. If + * not set, all environment classes are returned. + */ + enabled?: boolean | null; + + /** + * runner_ids filters the response to only EnvironmentClasses of these Runner IDs + */ + runnerIds?: Array<string>; + + /** + * runner_kind filters the response to only environment classes from runners of + * these kinds. + */ + runnerKinds?: Array<RunnersAPI.RunnerKind>; + + /** + * runner_providers filters the response to only environment classes from runners + * of these providers. + */ + runnerProviders?: Array<RunnersAPI.RunnerProvider>; + } + + /** + * pagination contains the pagination options for listing environment classes + */ + export interface Pagination { + /** + * Token for the next set of results that was returned as next_token of a + * PaginationResponse + */ + token?: string; + + /** + * Page size is the maximum number of results to retrieve per page. Defaults to 25. + * Maximum 100. + */ + pageSize?: number; + } +} + +export declare namespace EnvironmentClasses { + export { + type EnvironmentClassCreateResponse as EnvironmentClassCreateResponse, + type EnvironmentClassRetrieveResponse as EnvironmentClassRetrieveResponse, + type EnvironmentClassUpdateResponse as EnvironmentClassUpdateResponse, + type EnvironmentClassCreateParams as EnvironmentClassCreateParams, + type EnvironmentClassRetrieveParams as EnvironmentClassRetrieveParams, + type EnvironmentClassUpdateParams as EnvironmentClassUpdateParams, + type EnvironmentClassListParams as EnvironmentClassListParams, + }; +} + +export { type EnvironmentClassesEnvironmentClassesPage }; diff --git a/src/resources/runners/configurations/host-authentication-tokens.ts b/src/resources/runners/configurations/host-authentication-tokens.ts new file mode 100644 index 0000000..8196628 --- /dev/null +++ b/src/resources/runners/configurations/host-authentication-tokens.ts @@ -0,0 +1,558 @@ +// 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, TokensPage, type TokensPageParams } from '../../../core/pagination'; +import { RequestOptions } from '../../../internal/request-options'; + +export class HostAuthenticationTokens extends APIResource { + /** + * Creates a new authentication token for accessing remote hosts. + * + * Use this method to: + * + * - Set up SCM authentication + * - Configure OAuth credentials + * - Manage PAT tokens + * + * ### Examples + * + * - Create OAuth token: + * + * Creates a new OAuth-based authentication token. + * + * ```yaml + * runnerId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + * userId: "f53d2330-3795-4c5d-a1f3-453121af9c60" + * host: "github.com" + * token: "gho_xxxxxxxxxxxx" + * source: HOST_AUTHENTICATION_TOKEN_SOURCE_OAUTH + * expiresAt: "2024-12-31T23:59:59Z" + * refreshToken: "ghr_xxxxxxxxxxxx" + * ``` + */ + create( + body: HostAuthenticationTokenCreateParams, + options?: RequestOptions, + ): APIPromise<HostAuthenticationTokenCreateResponse> { + return this._client.post('/gitpod.v1.RunnerConfigurationService/CreateHostAuthenticationToken', { + body, + ...options, + }); + } + + /** + * Gets details about a specific host authentication token. + * + * Use this method to: + * + * - View token information + * - Check token expiration + * - Verify token validity + * + * ### Examples + * + * - Get token details: + * + * Retrieves information about a specific token. + * + * ```yaml + * id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + * ``` + */ + retrieve( + body: HostAuthenticationTokenRetrieveParams, + options?: RequestOptions, + ): APIPromise<HostAuthenticationTokenRetrieveResponse> { + return this._client.post('/gitpod.v1.RunnerConfigurationService/GetHostAuthenticationToken', { + body, + ...options, + }); + } + + /** + * Updates an existing host authentication token. + * + * Use this method to: + * + * - Refresh token values + * - Update expiration + * - Modify token settings + * + * ### Examples + * + * - Update token: + * + * Updates token value and expiration. + * + * ```yaml + * id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + * token: "gho_xxxxxxxxxxxx" + * expiresAt: "2024-12-31T23:59:59Z" + * refreshToken: "ghr_xxxxxxxxxxxx" + * ``` + */ + update(body: HostAuthenticationTokenUpdateParams, options?: RequestOptions): APIPromise<unknown> { + return this._client.post('/gitpod.v1.RunnerConfigurationService/UpdateHostAuthenticationToken', { + body, + ...options, + }); + } + + /** + * Lists host authentication tokens with optional filtering. + * + * Use this method to: + * + * - View all tokens + * - Filter by runner or user + * - Monitor token status + * + * ### Examples + * + * - List all tokens: + * + * Shows all tokens with pagination. + * + * ```yaml + * pagination: + * pageSize: 20 + * ``` + * + * - Filter by runner: + * + * Lists tokens for a specific runner. + * + * ```yaml + * filter: + * runnerId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + * pagination: + * pageSize: 20 + * ``` + */ + list( + params: HostAuthenticationTokenListParams, + options?: RequestOptions, + ): PagePromise<HostAuthenticationTokensTokensPage, HostAuthenticationToken> { + const { token, pageSize, ...body } = params; + return this._client.getAPIList( + '/gitpod.v1.RunnerConfigurationService/ListHostAuthenticationTokens', + TokensPage<HostAuthenticationToken>, + { query: { token, pageSize }, body, method: 'post', ...options }, + ); + } + + /** + * Deletes a host authentication token. + * + * Use this method to: + * + * - Remove unused tokens + * - Revoke access + * - Clean up expired tokens + * + * ### Examples + * + * - Delete token: + * + * Permanently removes a token. + * + * ```yaml + * id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + * ``` + */ + delete(body: HostAuthenticationTokenDeleteParams, options?: RequestOptions): APIPromise<unknown> { + return this._client.post('/gitpod.v1.RunnerConfigurationService/DeleteHostAuthenticationToken', { + body, + ...options, + }); + } +} + +export type HostAuthenticationTokensTokensPage = TokensPage<HostAuthenticationToken>; + +export interface HostAuthenticationToken { + id: string; + + /** + * A Timestamp represents a point in time independent of any time zone or local + * calendar, encoded as a count of seconds and fractions of seconds at nanosecond + * resolution. The count is relative to an epoch at UTC midnight on January 1, + * 1970, in the proleptic Gregorian calendar which extends the Gregorian calendar + * backwards to year one. + * + * All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap + * second table is needed for interpretation, using a + * [24-hour linear smear](https://developers.google.com/time/smear). + * + * The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By + * restricting to that range, we ensure that we can convert to and from + * [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. + * + * # Examples + * + * Example 1: Compute Timestamp from POSIX `time()`. + * + * Timestamp timestamp; + * timestamp.set_seconds(time(NULL)); + * timestamp.set_nanos(0); + * + * Example 2: Compute Timestamp from POSIX `gettimeofday()`. + * + * struct timeval tv; + * gettimeofday(&tv, NULL); + * + * Timestamp timestamp; + * timestamp.set_seconds(tv.tv_sec); + * timestamp.set_nanos(tv.tv_usec * 1000); + * + * Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. + * + * FILETIME ft; + * GetSystemTimeAsFileTime(&ft); + * UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; + * + * // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z + * // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. + * Timestamp timestamp; + * timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); + * timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); + * + * Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. + * + * long millis = System.currentTimeMillis(); + * + * Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) + * .setNanos((int) ((millis % 1000) * 1000000)).build(); + * + * Example 5: Compute Timestamp from Java `Instant.now()`. + * + * Instant now = Instant.now(); + * + * Timestamp timestamp = + * Timestamp.newBuilder().setSeconds(now.getEpochSecond()) + * .setNanos(now.getNano()).build(); + * + * Example 6: Compute Timestamp from current time in Python. + * + * timestamp = Timestamp() + * timestamp.GetCurrentTime() + * + * # JSON Mapping + * + * In JSON format, the Timestamp type is encoded as a string in the + * [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the format is + * "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" where {year} is always + * expressed using four digits while {month}, {day}, {hour}, {min}, and {sec} are + * zero-padded to two digits each. The fractional seconds, which can go up to 9 + * digits (i.e. up to 1 nanosecond resolution), are optional. The "Z" suffix + * indicates the timezone ("UTC"); the timezone is required. A proto3 JSON + * serializer should always use UTC (as indicated by "Z") when printing the + * Timestamp type and a proto3 JSON parser should be able to accept both UTC and + * other timezones (as indicated by an offset). + * + * For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past 01:30 UTC on + * January 15, 2017. + * + * In JavaScript, one can convert a Date object to this format using the standard + * [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) + * method. In Python, a standard `datetime.datetime` object can be converted to + * this format using + * [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with the + * time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use the + * Joda Time's + * [`ISODateTimeFormat.dateTime()`](<http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime()>) + * to obtain a formatter capable of generating timestamps in this format. + */ + expiresAt?: string; + + host?: string; + + runnerId?: string; + + source?: HostAuthenticationTokenSource; + + userId?: string; +} + +export type HostAuthenticationTokenSource = + | 'HOST_AUTHENTICATION_TOKEN_SOURCE_UNSPECIFIED' + | 'HOST_AUTHENTICATION_TOKEN_SOURCE_OAUTH' + | 'HOST_AUTHENTICATION_TOKEN_SOURCE_PAT'; + +export interface HostAuthenticationTokenCreateResponse { + token: HostAuthenticationToken; +} + +export interface HostAuthenticationTokenRetrieveResponse { + token: HostAuthenticationToken; +} + +export type HostAuthenticationTokenUpdateResponse = unknown; + +export type HostAuthenticationTokenDeleteResponse = unknown; + +export interface HostAuthenticationTokenCreateParams { + token?: string; + + /** + * A Timestamp represents a point in time independent of any time zone or local + * calendar, encoded as a count of seconds and fractions of seconds at nanosecond + * resolution. The count is relative to an epoch at UTC midnight on January 1, + * 1970, in the proleptic Gregorian calendar which extends the Gregorian calendar + * backwards to year one. + * + * All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap + * second table is needed for interpretation, using a + * [24-hour linear smear](https://developers.google.com/time/smear). + * + * The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By + * restricting to that range, we ensure that we can convert to and from + * [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. + * + * # Examples + * + * Example 1: Compute Timestamp from POSIX `time()`. + * + * Timestamp timestamp; + * timestamp.set_seconds(time(NULL)); + * timestamp.set_nanos(0); + * + * Example 2: Compute Timestamp from POSIX `gettimeofday()`. + * + * struct timeval tv; + * gettimeofday(&tv, NULL); + * + * Timestamp timestamp; + * timestamp.set_seconds(tv.tv_sec); + * timestamp.set_nanos(tv.tv_usec * 1000); + * + * Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. + * + * FILETIME ft; + * GetSystemTimeAsFileTime(&ft); + * UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; + * + * // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z + * // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. + * Timestamp timestamp; + * timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); + * timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); + * + * Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. + * + * long millis = System.currentTimeMillis(); + * + * Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) + * .setNanos((int) ((millis % 1000) * 1000000)).build(); + * + * Example 5: Compute Timestamp from Java `Instant.now()`. + * + * Instant now = Instant.now(); + * + * Timestamp timestamp = + * Timestamp.newBuilder().setSeconds(now.getEpochSecond()) + * .setNanos(now.getNano()).build(); + * + * Example 6: Compute Timestamp from current time in Python. + * + * timestamp = Timestamp() + * timestamp.GetCurrentTime() + * + * # JSON Mapping + * + * In JSON format, the Timestamp type is encoded as a string in the + * [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the format is + * "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" where {year} is always + * expressed using four digits while {month}, {day}, {hour}, {min}, and {sec} are + * zero-padded to two digits each. The fractional seconds, which can go up to 9 + * digits (i.e. up to 1 nanosecond resolution), are optional. The "Z" suffix + * indicates the timezone ("UTC"); the timezone is required. A proto3 JSON + * serializer should always use UTC (as indicated by "Z") when printing the + * Timestamp type and a proto3 JSON parser should be able to accept both UTC and + * other timezones (as indicated by an offset). + * + * For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past 01:30 UTC on + * January 15, 2017. + * + * In JavaScript, one can convert a Date object to this format using the standard + * [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) + * method. In Python, a standard `datetime.datetime` object can be converted to + * this format using + * [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with the + * time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use the + * Joda Time's + * [`ISODateTimeFormat.dateTime()`](<http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime()>) + * to obtain a formatter capable of generating timestamps in this format. + */ + expiresAt?: string; + + host?: string; + + refreshToken?: string; + + runnerId?: string; + + source?: HostAuthenticationTokenSource; + + userId?: string; +} + +export interface HostAuthenticationTokenRetrieveParams { + id?: string; +} + +export interface HostAuthenticationTokenUpdateParams { + id?: string; + + token?: string | null; + + /** + * A Timestamp represents a point in time independent of any time zone or local + * calendar, encoded as a count of seconds and fractions of seconds at nanosecond + * resolution. The count is relative to an epoch at UTC midnight on January 1, + * 1970, in the proleptic Gregorian calendar which extends the Gregorian calendar + * backwards to year one. + * + * All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap + * second table is needed for interpretation, using a + * [24-hour linear smear](https://developers.google.com/time/smear). + * + * The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By + * restricting to that range, we ensure that we can convert to and from + * [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. + * + * # Examples + * + * Example 1: Compute Timestamp from POSIX `time()`. + * + * Timestamp timestamp; + * timestamp.set_seconds(time(NULL)); + * timestamp.set_nanos(0); + * + * Example 2: Compute Timestamp from POSIX `gettimeofday()`. + * + * struct timeval tv; + * gettimeofday(&tv, NULL); + * + * Timestamp timestamp; + * timestamp.set_seconds(tv.tv_sec); + * timestamp.set_nanos(tv.tv_usec * 1000); + * + * Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. + * + * FILETIME ft; + * GetSystemTimeAsFileTime(&ft); + * UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; + * + * // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z + * // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. + * Timestamp timestamp; + * timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); + * timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); + * + * Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. + * + * long millis = System.currentTimeMillis(); + * + * Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) + * .setNanos((int) ((millis % 1000) * 1000000)).build(); + * + * Example 5: Compute Timestamp from Java `Instant.now()`. + * + * Instant now = Instant.now(); + * + * Timestamp timestamp = + * Timestamp.newBuilder().setSeconds(now.getEpochSecond()) + * .setNanos(now.getNano()).build(); + * + * Example 6: Compute Timestamp from current time in Python. + * + * timestamp = Timestamp() + * timestamp.GetCurrentTime() + * + * # JSON Mapping + * + * In JSON format, the Timestamp type is encoded as a string in the + * [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the format is + * "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" where {year} is always + * expressed using four digits while {month}, {day}, {hour}, {min}, and {sec} are + * zero-padded to two digits each. The fractional seconds, which can go up to 9 + * digits (i.e. up to 1 nanosecond resolution), are optional. The "Z" suffix + * indicates the timezone ("UTC"); the timezone is required. A proto3 JSON + * serializer should always use UTC (as indicated by "Z") when printing the + * Timestamp type and a proto3 JSON parser should be able to accept both UTC and + * other timezones (as indicated by an offset). + * + * For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past 01:30 UTC on + * January 15, 2017. + * + * In JavaScript, one can convert a Date object to this format using the standard + * [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) + * method. In Python, a standard `datetime.datetime` object can be converted to + * this format using + * [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with the + * time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use the + * Joda Time's + * [`ISODateTimeFormat.dateTime()`](<http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime()>) + * to obtain a formatter capable of generating timestamps in this format. + */ + expiresAt?: string | null; + + refreshToken?: string | null; +} + +export interface HostAuthenticationTokenListParams extends TokensPageParams { + /** + * Body param: + */ + filter?: HostAuthenticationTokenListParams.Filter; + + /** + * Body param: + */ + pagination?: HostAuthenticationTokenListParams.Pagination; +} + +export namespace HostAuthenticationTokenListParams { + export interface Filter { + runnerId?: string | null; + + userId?: string | null; + } + + export interface Pagination { + /** + * Token for the next set of results that was returned as next_token of a + * PaginationResponse + */ + token?: string; + + /** + * Page size is the maximum number of results to retrieve per page. Defaults to 25. + * Maximum 100. + */ + pageSize?: number; + } +} + +export interface HostAuthenticationTokenDeleteParams { + id?: string; +} + +export declare namespace HostAuthenticationTokens { + export { + type HostAuthenticationToken as HostAuthenticationToken, + type HostAuthenticationTokenSource as HostAuthenticationTokenSource, + type HostAuthenticationTokenCreateResponse as HostAuthenticationTokenCreateResponse, + type HostAuthenticationTokenRetrieveResponse as HostAuthenticationTokenRetrieveResponse, + type HostAuthenticationTokenUpdateResponse as HostAuthenticationTokenUpdateResponse, + type HostAuthenticationTokenDeleteResponse as HostAuthenticationTokenDeleteResponse, + type HostAuthenticationTokensTokensPage as HostAuthenticationTokensTokensPage, + type HostAuthenticationTokenCreateParams as HostAuthenticationTokenCreateParams, + type HostAuthenticationTokenRetrieveParams as HostAuthenticationTokenRetrieveParams, + type HostAuthenticationTokenUpdateParams as HostAuthenticationTokenUpdateParams, + type HostAuthenticationTokenListParams as HostAuthenticationTokenListParams, + type HostAuthenticationTokenDeleteParams as HostAuthenticationTokenDeleteParams, + }; +} diff --git a/src/resources/runners/configurations/index.ts b/src/resources/runners/configurations/index.ts new file mode 100644 index 0000000..4a0a213 --- /dev/null +++ b/src/resources/runners/configurations/index.ts @@ -0,0 +1,56 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export { + Configurations, + type EnvironmentClassValidationResult, + type FieldValidationError, + type ScmIntegrationValidationResult, + type ConfigurationValidateResponse, + type ConfigurationValidateParams, +} from './configurations'; +export { + EnvironmentClasses, + type EnvironmentClassCreateResponse, + type EnvironmentClassRetrieveResponse, + type EnvironmentClassUpdateResponse, + type EnvironmentClassCreateParams, + type EnvironmentClassRetrieveParams, + type EnvironmentClassUpdateParams, + type EnvironmentClassListParams, +} from './environment-classes'; +export { + HostAuthenticationTokens, + type HostAuthenticationToken, + type HostAuthenticationTokenSource, + type HostAuthenticationTokenCreateResponse, + type HostAuthenticationTokenRetrieveResponse, + type HostAuthenticationTokenUpdateResponse, + type HostAuthenticationTokenDeleteResponse, + type HostAuthenticationTokenCreateParams, + type HostAuthenticationTokenRetrieveParams, + type HostAuthenticationTokenUpdateParams, + type HostAuthenticationTokenListParams, + type HostAuthenticationTokenDeleteParams, + type HostAuthenticationTokensTokensPage, +} from './host-authentication-tokens'; +export { + Schema, + type RunnerConfigurationSchema, + type SchemaRetrieveResponse, + type SchemaRetrieveParams, +} from './schema'; +export { + ScmIntegrations, + type ScmIntegration, + type ScmIntegrationOAuthConfig, + type ScmIntegrationCreateResponse, + type ScmIntegrationRetrieveResponse, + type ScmIntegrationUpdateResponse, + type ScmIntegrationDeleteResponse, + type ScmIntegrationCreateParams, + type ScmIntegrationRetrieveParams, + type ScmIntegrationUpdateParams, + type ScmIntegrationListParams, + type ScmIntegrationDeleteParams, + type ScmIntegrationsIntegrationsPage, +} from './scm-integrations'; diff --git a/src/resources/runners/configurations/schema.ts b/src/resources/runners/configurations/schema.ts new file mode 100644 index 0000000..cd1222c --- /dev/null +++ b/src/resources/runners/configurations/schema.ts @@ -0,0 +1,259 @@ +// 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 { RequestOptions } from '../../../internal/request-options'; + +export class Schema extends APIResource { + /** + * Gets the latest runner configuration schema. + * + * Use this method to: + * + * - View available settings + * - Check configuration options + * - Validate configurations + * + * ### Examples + * + * - Get schema: + * + * Retrieves configuration schema for a runner. + * + * ```yaml + * runnerId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + * ``` + */ + retrieve(body: SchemaRetrieveParams, options?: RequestOptions): APIPromise<SchemaRetrieveResponse> { + return this._client.post('/gitpod.v1.RunnerConfigurationService/GetRunnerConfigurationSchema', { + body, + ...options, + }); + } +} + +export interface RunnerConfigurationSchema { + environmentClasses?: Array<RunnerConfigurationSchema.EnvironmentClass>; + + runnerConfig?: Array<RunnerConfigurationSchema.RunnerConfig>; + + scm?: Array<RunnerConfigurationSchema.Scm>; + + /** + * The schema version + */ + version?: string; +} + +export namespace RunnerConfigurationSchema { + export interface EnvironmentClass { + id?: string; + + bool?: EnvironmentClass.Bool; + + description?: string; + + display?: EnvironmentClass.Display; + + enum?: EnvironmentClass.Enum; + + int?: EnvironmentClass.Int; + + name?: string; + + required?: boolean; + + secret?: boolean; + + string?: EnvironmentClass.String; + } + + export namespace EnvironmentClass { + export interface Bool { + default?: boolean; + } + + export interface Display { + default?: string; + } + + export interface Enum { + /** + * @deprecated deprecated, will be removed, use default_value instead + */ + default?: string; + + defaultValue?: Enum.DefaultValue; + + possibleValues?: Array<Enum.PossibleValue>; + + /** + * @deprecated deprecated, will be removed, use possible_values instead + */ + values?: Array<string>; + } + + export namespace Enum { + export interface DefaultValue { + detail?: string; + + subtitle?: string; + + title?: string; + } + + export interface PossibleValue { + detail?: string; + + subtitle?: string; + + title?: string; + } + } + + export interface Int { + default?: number; + + max?: number; + + min?: number; + } + + export interface String { + default?: string; + + pattern?: string; + } + } + + export interface RunnerConfig { + id?: string; + + bool?: RunnerConfig.Bool; + + description?: string; + + display?: RunnerConfig.Display; + + enum?: RunnerConfig.Enum; + + int?: RunnerConfig.Int; + + name?: string; + + required?: boolean; + + secret?: boolean; + + string?: RunnerConfig.String; + } + + export namespace RunnerConfig { + export interface Bool { + default?: boolean; + } + + export interface Display { + default?: string; + } + + export interface Enum { + /** + * @deprecated deprecated, will be removed, use default_value instead + */ + default?: string; + + defaultValue?: Enum.DefaultValue; + + possibleValues?: Array<Enum.PossibleValue>; + + /** + * @deprecated deprecated, will be removed, use possible_values instead + */ + values?: Array<string>; + } + + export namespace Enum { + export interface DefaultValue { + detail?: string; + + subtitle?: string; + + title?: string; + } + + export interface PossibleValue { + detail?: string; + + subtitle?: string; + + title?: string; + } + } + + export interface Int { + default?: number; + + max?: number; + + min?: number; + } + + export interface String { + default?: string; + + pattern?: string; + } + } + + export interface Scm { + defaultHosts?: Array<string>; + + name?: string; + + oauth?: Scm.OAuth; + + pat?: Scm.Pat; + + scmId?: string; + } + + export namespace Scm { + export interface OAuth { + /** + * callback_url is the URL the OAuth app will redirect to after the user has + * authenticated. + */ + callbackUrl?: string; + } + + export interface Pat { + /** + * description is a human-readable description of the PAT. + */ + description?: string; + + /** + * docs_link is a link to the documentation on how to create a PAT for this SCM + * system. + */ + docsLink?: string; + } + } +} + +export interface SchemaRetrieveResponse { + schema?: RunnerConfigurationSchema; +} + +export interface SchemaRetrieveParams { + runnerId?: string; +} + +export declare namespace Schema { + export { + type RunnerConfigurationSchema as RunnerConfigurationSchema, + type SchemaRetrieveResponse as SchemaRetrieveResponse, + type SchemaRetrieveParams as SchemaRetrieveParams, + }; +} diff --git a/src/resources/runners/configurations/scm-integrations.ts b/src/resources/runners/configurations/scm-integrations.ts new file mode 100644 index 0000000..ebdc52b --- /dev/null +++ b/src/resources/runners/configurations/scm-integrations.ts @@ -0,0 +1,326 @@ +// 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 { IntegrationsPage, type IntegrationsPageParams, PagePromise } from '../../../core/pagination'; +import { RequestOptions } from '../../../internal/request-options'; + +export class ScmIntegrations extends APIResource { + /** + * Creates a new SCM integration for a runner. + * + * Use this method to: + * + * - Configure source control access + * - Set up repository integrations + * - Enable code synchronization + * + * ### Examples + * + * - Create GitHub integration: + * + * Sets up GitHub SCM integration. + * + * ```yaml + * runnerId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + * scmId: "github" + * host: "github.com" + * oauthClientId: "client_id" + * oauthPlaintextClientSecret: "client_secret" + * ``` + */ + create( + body: ScmIntegrationCreateParams, + options?: RequestOptions, + ): APIPromise<ScmIntegrationCreateResponse> { + return this._client.post('/gitpod.v1.RunnerConfigurationService/CreateSCMIntegration', { + body, + ...options, + }); + } + + /** + * Gets details about a specific SCM integration. + * + * Use this method to: + * + * - View integration settings + * - Check integration status + * - Verify configuration + * + * ### Examples + * + * - Get integration details: + * + * Retrieves information about a specific integration. + * + * ```yaml + * id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + * ``` + */ + retrieve( + body: ScmIntegrationRetrieveParams, + options?: RequestOptions, + ): APIPromise<ScmIntegrationRetrieveResponse> { + return this._client.post('/gitpod.v1.RunnerConfigurationService/GetSCMIntegration', { body, ...options }); + } + + /** + * Updates an existing SCM integration. + * + * Use this method to: + * + * - Modify integration settings + * - Update credentials + * - Change configuration + * + * ### Examples + * + * - Update integration: + * + * Updates OAuth credentials. + * + * ```yaml + * id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + * oauthClientId: "new_client_id" + * oauthPlaintextClientSecret: "new_client_secret" + * ``` + */ + update(body: ScmIntegrationUpdateParams, options?: RequestOptions): APIPromise<unknown> { + return this._client.post('/gitpod.v1.RunnerConfigurationService/UpdateSCMIntegration', { + body, + ...options, + }); + } + + /** + * Lists SCM integrations for a runner. + * + * Use this method to: + * + * - View all integrations + * - Monitor integration status + * - Check available SCMs + * + * ### Examples + * + * - List integrations: + * + * Shows all SCM integrations. + * + * ```yaml + * filter: + * runnerIds: ["d2c94c27-3b76-4a42-b88c-95a85e392c68"] + * pagination: + * pageSize: 20 + * ``` + */ + list( + params: ScmIntegrationListParams, + options?: RequestOptions, + ): PagePromise<ScmIntegrationsIntegrationsPage, ScmIntegration> { + const { token, pageSize, ...body } = params; + return this._client.getAPIList( + '/gitpod.v1.RunnerConfigurationService/ListSCMIntegrations', + IntegrationsPage<ScmIntegration>, + { query: { token, pageSize }, body, method: 'post', ...options }, + ); + } + + /** + * Deletes an SCM integration. + * + * Use this method to: + * + * - Remove unused integrations + * - Clean up configurations + * - Revoke SCM access + * + * ### Examples + * + * - Delete integration: + * + * Removes an SCM integration. + * + * ```yaml + * id: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + * ``` + */ + delete(body: ScmIntegrationDeleteParams, options?: RequestOptions): APIPromise<unknown> { + return this._client.post('/gitpod.v1.RunnerConfigurationService/DeleteSCMIntegration', { + body, + ...options, + }); + } +} + +export type ScmIntegrationsIntegrationsPage = IntegrationsPage<ScmIntegration>; + +export interface ScmIntegration { + /** + * id is the unique identifier of the SCM integration + */ + id?: string; + + host?: string; + + oauth?: ScmIntegrationOAuthConfig | null; + + pat?: boolean; + + runnerId?: string; + + /** + * scm_id references the scm_id in the runner's configuration schema that this + * integration is for + */ + scmId?: string; +} + +export interface ScmIntegrationOAuthConfig { + /** + * client_id is the OAuth app's client ID in clear text. + */ + clientId?: string; + + /** + * encrypted_client_secret is the OAuth app's secret encrypted with the runner's + * public key. + */ + encryptedClientSecret?: string; +} + +export interface ScmIntegrationCreateResponse { + /** + * id is a uniquely generated identifier for the SCM integration + */ + id?: string; +} + +export interface ScmIntegrationRetrieveResponse { + integration?: ScmIntegration; +} + +export type ScmIntegrationUpdateResponse = unknown; + +export type ScmIntegrationDeleteResponse = unknown; + +export interface ScmIntegrationCreateParams { + host?: string; + + /** + * oauth_client_id is the OAuth app's client ID, if OAuth is configured. If + * configured, oauth_plaintext_client_secret must also be set. + */ + oauthClientId?: string | null; + + /** + * oauth_plaintext_client_secret is the OAuth app's client secret in clear text. + * This will first be encrypted with the runner's public key before being stored. + */ + oauthPlaintextClientSecret?: string | null; + + pat?: boolean; + + runnerId?: string; + + /** + * scm_id references the scm_id in the runner's configuration schema that this + * integration is for + */ + scmId?: string; +} + +export interface ScmIntegrationRetrieveParams { + id?: string; +} + +export interface ScmIntegrationUpdateParams { + id?: string; + + /** + * oauth_client_id can be set to update the OAuth app's client ID. If an empty + * string is set, the OAuth configuration will be removed (regardless of whether a + * client secret is set), and any existing Host Authentication Tokens for the SCM + * integration's runner and host that were created using the OAuth app will be + * deleted. This might lead to users being unable to access their repositories + * until they re-authenticate. + */ + oauthClientId?: string | null; + + /** + * oauth_plaintext_client_secret can be set to update the OAuth app's client + * secret. The cleartext secret will be encrypted with the runner's public key + * before being stored. + */ + oauthPlaintextClientSecret?: string | null; + + /** + * pat can be set to enable or disable Personal Access Tokens support. When + * disabling PATs, any existing Host Authentication Tokens for the SCM + * integration's runner and host that were created using a PAT will be deleted. + * This might lead to users being unable to access their repositories until they + * re-authenticate. + */ + pat?: boolean | null; +} + +export interface ScmIntegrationListParams extends IntegrationsPageParams { + /** + * Body param: + */ + filter?: ScmIntegrationListParams.Filter; + + /** + * Body param: pagination contains the pagination options for listing scm + * integrations + */ + pagination?: ScmIntegrationListParams.Pagination; +} + +export namespace ScmIntegrationListParams { + export interface Filter { + /** + * runner_ids filters the response to only SCM integrations of these Runner IDs + */ + runnerIds?: Array<string>; + } + + /** + * pagination contains the pagination options for listing scm integrations + */ + export interface Pagination { + /** + * Token for the next set of results that was returned as next_token of a + * PaginationResponse + */ + token?: string; + + /** + * Page size is the maximum number of results to retrieve per page. Defaults to 25. + * Maximum 100. + */ + pageSize?: number; + } +} + +export interface ScmIntegrationDeleteParams { + id?: string; +} + +export declare namespace ScmIntegrations { + export { + type ScmIntegration as ScmIntegration, + type ScmIntegrationOAuthConfig as ScmIntegrationOAuthConfig, + type ScmIntegrationCreateResponse as ScmIntegrationCreateResponse, + type ScmIntegrationRetrieveResponse as ScmIntegrationRetrieveResponse, + type ScmIntegrationUpdateResponse as ScmIntegrationUpdateResponse, + type ScmIntegrationDeleteResponse as ScmIntegrationDeleteResponse, + type ScmIntegrationsIntegrationsPage as ScmIntegrationsIntegrationsPage, + type ScmIntegrationCreateParams as ScmIntegrationCreateParams, + type ScmIntegrationRetrieveParams as ScmIntegrationRetrieveParams, + type ScmIntegrationUpdateParams as ScmIntegrationUpdateParams, + type ScmIntegrationListParams as ScmIntegrationListParams, + type ScmIntegrationDeleteParams as ScmIntegrationDeleteParams, + }; +} diff --git a/src/resources/runners/index.ts b/src/resources/runners/index.ts new file mode 100644 index 0000000..0f5a99a --- /dev/null +++ b/src/resources/runners/index.ts @@ -0,0 +1,53 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export { + Configurations, + type EnvironmentClassValidationResult, + type FieldValidationError, + type ScmIntegrationValidationResult, + type ConfigurationValidateResponse, + type ConfigurationValidateParams, +} from './configurations/index'; +export { + Policies, + type RunnerPolicy, + type RunnerRole, + type PolicyCreateResponse, + type PolicyUpdateResponse, + type PolicyDeleteResponse, + type PolicyCreateParams, + type PolicyUpdateParams, + type PolicyListParams, + type PolicyDeleteParams, + type RunnerPoliciesPoliciesPage, +} from './policies'; +export { + Runners, + type LogLevel, + type MetricsConfiguration, + type Runner, + type RunnerCapability, + type RunnerConfiguration, + type RunnerKind, + type RunnerPhase, + type RunnerProvider, + type RunnerReleaseChannel, + type RunnerSpec, + type RunnerStatus, + type RunnerCreateResponse, + type RunnerRetrieveResponse, + type RunnerUpdateResponse, + type RunnerDeleteResponse, + type RunnerCheckAuthenticationForHostResponse, + type RunnerCreateRunnerTokenResponse, + type RunnerParseContextURLResponse, + type RunnerCreateParams, + type RunnerRetrieveParams, + type RunnerUpdateParams, + type RunnerListParams, + type RunnerDeleteParams, + type RunnerCheckAuthenticationForHostParams, + type RunnerCreateRunnerTokenParams, + type RunnerParseContextURLParams, + type RunnersRunnersPage, +} from './runners'; diff --git a/src/resources/runners/policies.ts b/src/resources/runners/policies.ts new file mode 100644 index 0000000..0cdd4c1 --- /dev/null +++ b/src/resources/runners/policies.ts @@ -0,0 +1,225 @@ +// 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, PoliciesPage, type PoliciesPageParams } from '../../core/pagination'; +import { RequestOptions } from '../../internal/request-options'; + +export class Policies extends APIResource { + /** + * Creates a new policy for a runner. + * + * Use this method to: + * + * - Set up access controls + * - Define group permissions + * - Configure role-based access + * + * ### Examples + * + * - Create admin policy: + * + * Grants admin access to a group. + * + * ```yaml + * runnerId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + * groupId: "f53d2330-3795-4c5d-a1f3-453121af9c60" + * role: RUNNER_ROLE_ADMIN + * ``` + */ + create(body: PolicyCreateParams, options?: RequestOptions): APIPromise<PolicyCreateResponse> { + return this._client.post('/gitpod.v1.RunnerService/CreateRunnerPolicy', { body, ...options }); + } + + /** + * Updates an existing runner policy. + * + * Use this method to: + * + * - Modify access levels + * - Change group roles + * - Update permissions + * + * ### Examples + * + * - Update policy role: + * + * Changes a group's access level. + * + * ```yaml + * runnerId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + * groupId: "f53d2330-3795-4c5d-a1f3-453121af9c60" + * role: RUNNER_ROLE_USER + * ``` + */ + update(body: PolicyUpdateParams, options?: RequestOptions): APIPromise<PolicyUpdateResponse> { + return this._client.post('/gitpod.v1.RunnerService/UpdateRunnerPolicy', { body, ...options }); + } + + /** + * Lists policies for a runner. + * + * Use this method to: + * + * - View access controls + * - Check policy configurations + * - Audit permissions + * + * ### Examples + * + * - List policies: + * + * Shows all policies for a runner. + * + * ```yaml + * runnerId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + * pagination: + * pageSize: 20 + * ``` + */ + list( + params: PolicyListParams, + options?: RequestOptions, + ): PagePromise<RunnerPoliciesPoliciesPage, RunnerPolicy> { + const { token, pageSize, ...body } = params; + return this._client.getAPIList( + '/gitpod.v1.RunnerService/ListRunnerPolicies', + PoliciesPage<RunnerPolicy>, + { query: { token, pageSize }, body, method: 'post', ...options }, + ); + } + + /** + * Deletes a runner policy. + * + * Use this method to: + * + * - Remove access controls + * - Revoke permissions + * - Clean up policies + * + * ### Examples + * + * - Delete policy: + * + * Removes a group's access policy. + * + * ```yaml + * runnerId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + * groupId: "f53d2330-3795-4c5d-a1f3-453121af9c60" + * ``` + */ + delete(body: PolicyDeleteParams, options?: RequestOptions): APIPromise<unknown> { + return this._client.post('/gitpod.v1.RunnerService/DeleteRunnerPolicy', { body, ...options }); + } +} + +export type RunnerPoliciesPoliciesPage = PoliciesPage<RunnerPolicy>; + +export interface RunnerPolicy { + groupId?: string; + + /** + * role is the role assigned to the group + */ + role?: RunnerRole; +} + +export type RunnerRole = 'RUNNER_ROLE_UNSPECIFIED' | 'RUNNER_ROLE_ADMIN' | 'RUNNER_ROLE_USER'; + +export interface PolicyCreateResponse { + policy: RunnerPolicy; +} + +export interface PolicyUpdateResponse { + policy: RunnerPolicy; +} + +export type PolicyDeleteResponse = unknown; + +export interface PolicyCreateParams { + /** + * group_id specifies the group_id identifier + */ + groupId?: string; + + role?: RunnerRole; + + /** + * runner_id specifies the project identifier + */ + runnerId?: string; +} + +export interface PolicyUpdateParams { + /** + * group_id specifies the group_id identifier + */ + groupId?: string; + + role?: RunnerRole; + + /** + * runner_id specifies the project identifier + */ + runnerId?: string; +} + +export interface PolicyListParams extends PoliciesPageParams { + /** + * Body param: pagination contains the pagination options for listing project + * policies + */ + pagination?: PolicyListParams.Pagination; + + /** + * Body param: runner_id specifies the project identifier + */ + runnerId?: string; +} + +export namespace PolicyListParams { + /** + * pagination contains the pagination options for listing project policies + */ + export interface Pagination { + /** + * Token for the next set of results that was returned as next_token of a + * PaginationResponse + */ + token?: string; + + /** + * Page size is the maximum number of results to retrieve per page. Defaults to 25. + * Maximum 100. + */ + pageSize?: number; + } +} + +export interface PolicyDeleteParams { + /** + * group_id specifies the group_id identifier + */ + groupId?: string; + + /** + * runner_id specifies the project identifier + */ + runnerId?: string; +} + +export declare namespace Policies { + export { + type RunnerPolicy as RunnerPolicy, + type RunnerRole as RunnerRole, + type PolicyCreateResponse as PolicyCreateResponse, + type PolicyUpdateResponse as PolicyUpdateResponse, + type PolicyDeleteResponse as PolicyDeleteResponse, + type RunnerPoliciesPoliciesPage as RunnerPoliciesPoliciesPage, + type PolicyCreateParams as PolicyCreateParams, + type PolicyUpdateParams as PolicyUpdateParams, + type PolicyListParams as PolicyListParams, + type PolicyDeleteParams as PolicyDeleteParams, + }; +} diff --git a/src/resources/runners/runners.ts b/src/resources/runners/runners.ts new file mode 100644 index 0000000..5abb6dd --- /dev/null +++ b/src/resources/runners/runners.ts @@ -0,0 +1,898 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../../core/resource'; +import * as RunnersAPI from './runners'; +import * as Shared from '../shared'; +import * as PoliciesAPI from './policies'; +import { + Policies, + PolicyCreateParams, + PolicyCreateResponse, + PolicyDeleteParams, + PolicyDeleteResponse, + PolicyListParams, + PolicyUpdateParams, + PolicyUpdateResponse, + RunnerPoliciesPoliciesPage, + RunnerPolicy, + RunnerRole, +} from './policies'; +import * as ConfigurationsAPI from './configurations/configurations'; +import { + ConfigurationValidateParams, + ConfigurationValidateResponse, + Configurations, + EnvironmentClassValidationResult, + FieldValidationError, + ScmIntegrationValidationResult, +} from './configurations/configurations'; +import { APIPromise } from '../../core/api-promise'; +import { PagePromise, RunnersPage, type RunnersPageParams } from '../../core/pagination'; +import { RequestOptions } from '../../internal/request-options'; + +export class Runners extends APIResource { + configurations: ConfigurationsAPI.Configurations = new ConfigurationsAPI.Configurations(this._client); + policies: PoliciesAPI.Policies = new PoliciesAPI.Policies(this._client); + + /** + * Creates a new runner registration with the server. Registrations are very + * short-lived and must be renewed every 30 seconds. + * + * Use this method to: + * + * - Register organization runners + * - Set up runner configurations + * - Initialize runner credentials + * - Configure auto-updates + * + * ### Examples + * + * - Create cloud runner: + * + * Creates a new runner in AWS EC2. + * + * ```yaml + * name: "Production Runner" + * provider: RUNNER_PROVIDER_AWS_EC2 + * spec: + * desiredPhase: RUNNER_PHASE_ACTIVE + * configuration: + * region: "us-west" + * releaseChannel: RUNNER_RELEASE_CHANNEL_STABLE + * autoUpdate: true + * ``` + * + * - Create local runner: + * + * Creates a new local runner on Linux. + * + * ```yaml + * name: "Local Development Runner" + * provider: RUNNER_PROVIDER_LINUX_HOST + * spec: + * desiredPhase: RUNNER_PHASE_ACTIVE + * configuration: + * releaseChannel: RUNNER_RELEASE_CHANNEL_LATEST + * autoUpdate: true + * ``` + */ + create(body: RunnerCreateParams, options?: RequestOptions): APIPromise<RunnerCreateResponse> { + return this._client.post('/gitpod.v1.RunnerService/CreateRunner', { body, ...options }); + } + + /** + * Gets details about a specific runner. + * + * Use this method to: + * + * - Check runner status + * - View runner configuration + * - Monitor runner health + * - Verify runner capabilities + * + * ### Examples + * + * - Get runner details: + * + * Retrieves information about a specific runner. + * + * ```yaml + * runnerId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + * ``` + */ + retrieve(body: RunnerRetrieveParams, options?: RequestOptions): APIPromise<RunnerRetrieveResponse> { + return this._client.post('/gitpod.v1.RunnerService/GetRunner', { body, ...options }); + } + + /** + * Updates a runner's configuration. + * + * Use this method to: + * + * - Modify runner settings + * - Update release channels + * - Change runner status + * - Configure auto-update settings + * + * ### Examples + * + * - Update configuration: + * + * Changes runner settings. + * + * ```yaml + * runnerId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + * name: "Updated Runner Name" + * spec: + * configuration: + * releaseChannel: RUNNER_RELEASE_CHANNEL_LATEST + * autoUpdate: true + * ``` + */ + update(body: RunnerUpdateParams, options?: RequestOptions): APIPromise<unknown> { + return this._client.post('/gitpod.v1.RunnerService/UpdateRunner', { body, ...options }); + } + + /** + * Lists all registered runners with optional filtering. + * + * Use this method to: + * + * - View all available runners + * - Filter by runner type + * - Monitor runner status + * - Check runner availability + * + * ### Examples + * + * - List all runners: + * + * Shows all runners with pagination. + * + * ```yaml + * pagination: + * pageSize: 20 + * ``` + * + * - Filter by provider: + * + * Lists only AWS EC2 runners. + * + * ```yaml + * filter: + * providers: ["RUNNER_PROVIDER_AWS_EC2"] + * pagination: + * pageSize: 20 + * ``` + */ + list(params: RunnerListParams, options?: RequestOptions): PagePromise<RunnersRunnersPage, Runner> { + const { token, pageSize, ...body } = params; + return this._client.getAPIList('/gitpod.v1.RunnerService/ListRunners', RunnersPage<Runner>, { + query: { token, pageSize }, + body, + method: 'post', + ...options, + }); + } + + /** + * Deletes a runner permanently. + * + * Use this method to: + * + * - Remove unused runners + * - Clean up runner registrations + * - Delete obsolete runners + * + * ### Examples + * + * - Delete runner: + * + * Permanently removes a runner. + * + * ```yaml + * runnerId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + * ``` + */ + delete(body: RunnerDeleteParams, options?: RequestOptions): APIPromise<unknown> { + return this._client.post('/gitpod.v1.RunnerService/DeleteRunner', { body, ...options }); + } + + /** + * Checks if a user is authenticated for a specific host. + * + * Use this method to: + * + * - Verify authentication status + * - Get authentication URLs + * - Check PAT support + * + * ### Examples + * + * - Check authentication: + * + * Verifies authentication for a host. + * + * ```yaml + * host: "github.com" + * ``` + */ + checkAuthenticationForHost( + body: RunnerCheckAuthenticationForHostParams, + options?: RequestOptions, + ): APIPromise<RunnerCheckAuthenticationForHostResponse> { + return this._client.post('/gitpod.v1.RunnerService/CheckAuthenticationForHost', { body, ...options }); + } + + /** + * Creates a new authentication token for a runner. + * + * Use this method to: + * + * - Generate runner credentials + * - Renew expired tokens + * - Set up runner authentication + * + * Note: This does not expire previously issued tokens. + * + * ### Examples + * + * - Create token: + * + * Creates a new token for runner authentication. + * + * ```yaml + * runnerId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + * ``` + */ + createRunnerToken( + body: RunnerCreateRunnerTokenParams, + options?: RequestOptions, + ): APIPromise<RunnerCreateRunnerTokenResponse> { + return this._client.post('/gitpod.v1.RunnerService/CreateRunnerToken', { body, ...options }); + } + + /** + * Parses a context URL and returns the parsed result. + * + * Use this method to: + * + * - Validate context URLs + * - Check repository access + * - Verify branch existence + * + * Returns: + * + * - FAILED_PRECONDITION if authentication is required + * - PERMISSION_DENIED if access is not allowed + * - INVALID_ARGUMENT if URL is invalid + * - NOT_FOUND if repository/branch doesn't exist + * + * ### Examples + * + * - Parse URL: + * + * Parses and validates a context URL. + * + * ```yaml + * contextUrl: "https://github.com/org/repo/tree/main" + * ``` + */ + parseContextURL( + body: RunnerParseContextURLParams, + options?: RequestOptions, + ): APIPromise<RunnerParseContextURLResponse> { + return this._client.post('/gitpod.v1.RunnerService/ParseContextURL', { body, ...options }); + } +} + +export type RunnersRunnersPage = RunnersPage<Runner>; + +export type LogLevel = + | 'LOG_LEVEL_UNSPECIFIED' + | 'LOG_LEVEL_DEBUG' + | 'LOG_LEVEL_INFO' + | 'LOG_LEVEL_WARN' + | 'LOG_LEVEL_ERROR'; + +export interface MetricsConfiguration { + /** + * enabled indicates whether the runner should collect metrics + */ + enabled?: boolean; + + /** + * password is the password to use for the metrics collector + */ + password?: string; + + /** + * url is the URL of the metrics collector + */ + url?: string; + + /** + * username is the username to use for the metrics collector + */ + username?: string; +} + +export interface Runner { + /** + * Time when the Runner was created. + */ + createdAt?: string; + + /** + * creator is the identity of the creator of the environment + */ + creator?: Shared.Subject; + + /** + * The runner's kind + */ + kind?: RunnerKind; + + /** + * The runner's name which is shown to users + */ + name?: string; + + /** + * The runner's provider + */ + provider?: RunnerProvider; + + runnerId?: string; + + /** + * The runner's specification + */ + spec?: RunnerSpec; + + /** + * The runner's status + */ + status?: RunnerStatus; + + /** + * Time when the Runner was last udpated. + */ + updatedAt?: string; +} + +export type RunnerCapability = + | 'RUNNER_CAPABILITY_UNSPECIFIED' + | 'RUNNER_CAPABILITY_FETCH_LOCAL_SCM_INTEGRATIONS' + | 'RUNNER_CAPABILITY_SECRET_CONTAINER_REGISTRY' + | 'RUNNER_CAPABILITY_AGENT_EXECUTION' + | 'RUNNER_CAPABILITY_ALLOW_ENV_TOKEN_POPULATION' + | 'RUNNER_CAPABILITY_DEFAULT_DEV_CONTAINER_IMAGE'; + +export interface RunnerConfiguration { + /** + * auto_update indicates whether the runner should automatically update itself. + */ + autoUpdate?: boolean; + + /** + * devcontainer_image_cache_enabled controls whether the devcontainer build cache + * is enabled for this runner. Only takes effect on supported runners, currently + * only AWS EC2 runners. + */ + devcontainerImageCacheEnabled?: boolean; + + /** + * log_level is the log level for the runner + */ + logLevel?: LogLevel; + + /** + * metrics contains configuration for the runner's metrics collection + */ + metrics?: MetricsConfiguration; + + /** + * Region to deploy the runner in, if applicable. This is mainly used for remote + * runners, and is only a hint. The runner may be deployed in a different region. + * See the runner's status for the actual region. + */ + region?: string; + + /** + * The release channel the runner is on + */ + releaseChannel?: RunnerReleaseChannel; +} + +/** + * RunnerKind represents the kind of a runner + */ +export type RunnerKind = + | 'RUNNER_KIND_UNSPECIFIED' + | 'RUNNER_KIND_LOCAL' + | 'RUNNER_KIND_REMOTE' + | 'RUNNER_KIND_LOCAL_CONFIGURATION'; + +/** + * RunnerPhase represents the phase a runner is in + */ +export type RunnerPhase = + | 'RUNNER_PHASE_UNSPECIFIED' + | 'RUNNER_PHASE_CREATED' + | 'RUNNER_PHASE_INACTIVE' + | 'RUNNER_PHASE_ACTIVE' + | 'RUNNER_PHASE_DELETING' + | 'RUNNER_PHASE_DELETED' + | 'RUNNER_PHASE_DEGRADED'; + +/** + * RunnerProvider identifies the specific implementation type of a runner. Each + * provider maps to a specific kind of runner (local or remote), as specified below + * for each provider. + */ +export type RunnerProvider = + | 'RUNNER_PROVIDER_UNSPECIFIED' + | 'RUNNER_PROVIDER_AWS_EC2' + | 'RUNNER_PROVIDER_LINUX_HOST' + | 'RUNNER_PROVIDER_DESKTOP_MAC'; + +export type RunnerReleaseChannel = + | 'RUNNER_RELEASE_CHANNEL_UNSPECIFIED' + | 'RUNNER_RELEASE_CHANNEL_STABLE' + | 'RUNNER_RELEASE_CHANNEL_LATEST'; + +export interface RunnerSpec { + /** + * The runner's configuration + */ + configuration?: RunnerConfiguration; + + /** + * RunnerPhase represents the phase a runner is in + */ + desiredPhase?: RunnerPhase; +} + +/** + * RunnerStatus represents the status of a runner + */ +export interface RunnerStatus { + /** + * additional_info contains additional information about the runner, e.g. a + * CloudFormation stack URL. + */ + additionalInfo?: Array<Shared.FieldValue>; + + /** + * capabilities is a list of capabilities the runner supports. + */ + capabilities?: Array<RunnerCapability>; + + logUrl?: string; + + /** + * The runner's reported message which is shown to users. This message adds more + * context to the runner's phase. + */ + message?: string; + + /** + * The runner's reported phase + */ + phase?: RunnerPhase; + + /** + * region is the region the runner is running in, if applicable. + */ + region?: string; + + systemDetails?: string; + + /** + * Time when the status was last udpated. + */ + updatedAt?: string; + + version?: string; +} + +export interface RunnerCreateResponse { + runner: Runner; + + /** + * @deprecated deprecated, will be removed. Use exchange_token instead. + */ + accessToken?: string; + + /** + * exchange_token is a one-time use token that should be exchanged by the runner + * for an access token, using the IdentityService.ExchangeToken rpc. The token + * expires after 24 hours. + */ + exchangeToken?: string; +} + +export interface RunnerRetrieveResponse { + runner: Runner; +} + +export type RunnerUpdateResponse = unknown; + +export type RunnerDeleteResponse = unknown; + +export interface RunnerCheckAuthenticationForHostResponse { + authenticated?: boolean; + + /** + * @deprecated + */ + authenticationUrl?: string; + + /** + * @deprecated + */ + patSupported?: boolean; + + /** + * scm_id is the unique identifier of the SCM provider + */ + scmId?: string; + + /** + * scm_name is the human-readable name of the SCM provider (e.g., "GitHub", + * "GitLab") + */ + scmName?: string; + + /** + * supports_oauth2 indicates that the host supports OAuth2 authentication + */ + supportsOauth2?: RunnerCheckAuthenticationForHostResponse.SupportsOauth2; + + /** + * supports_pat indicates that the host supports Personal Access Token + * authentication + */ + supportsPat?: RunnerCheckAuthenticationForHostResponse.SupportsPat; +} + +export namespace RunnerCheckAuthenticationForHostResponse { + /** + * supports_oauth2 indicates that the host supports OAuth2 authentication + */ + export interface SupportsOauth2 { + /** + * auth_url is the URL where users can authenticate + */ + authUrl?: string; + + /** + * docs_url is the URL to the documentation explaining this authentication method + */ + docsUrl?: string; + } + + /** + * supports_pat indicates that the host supports Personal Access Token + * authentication + */ + export interface SupportsPat { + /** + * create_url is the URL where users can create a new Personal Access Token + */ + createUrl?: string; + + /** + * docs_url is the URL to the documentation explaining PAT usage for this host + */ + docsUrl?: string; + + /** + * example is an example of a Personal Access Token + */ + example?: string; + + /** + * required_scopes is the list of permissions required for the Personal Access + * Token + */ + requiredScopes?: Array<string>; + } +} + +export interface RunnerCreateRunnerTokenResponse { + /** + * @deprecated deprecated, will be removed. Use exchange_token instead. + */ + accessToken?: string; + + /** + * exchange_token is a one-time use token that should be exchanged by the runner + * for an access token, using the IdentityService.ExchangeToken rpc. The token + * expires after 24 hours. + */ + exchangeToken?: string; +} + +export interface RunnerParseContextURLResponse { + git?: RunnerParseContextURLResponse.Git; + + originalContextUrl?: string; + + /** + * project_ids is a list of projects to which the context URL belongs to. + */ + projectIds?: Array<string>; +} + +export namespace RunnerParseContextURLResponse { + export interface Git { + branch?: string; + + cloneUrl?: string; + + commit?: string; + + host?: string; + + owner?: string; + + repo?: string; + + upstreamRemoteUrl?: string; + } +} + +export interface RunnerCreateParams { + /** + * The runner's kind This field is optional and here for backwards-compatibility. + * Use the provider field instead. If provider is set, the runner's kind will be + * deduced from the provider. Only one of kind and provider must be set. + */ + kind?: RunnerKind; + + /** + * The runner name for humans + */ + name?: string; + + /** + * The specific implementation type of the runner This field is optional for + * backwards compatibility but will be required in the future. When specified, kind + * must not be specified (will be deduced from provider) + */ + provider?: RunnerProvider; + + spec?: RunnerSpec; +} + +export interface RunnerRetrieveParams { + runnerId?: string; +} + +export interface RunnerUpdateParams { + /** + * The runner's name which is shown to users + */ + name?: string | null; + + /** + * runner_id specifies which runner to be updated. + * + * +required + */ + runnerId?: string; + + spec?: RunnerUpdateParams.Spec | null; +} + +export namespace RunnerUpdateParams { + export interface Spec { + configuration?: Spec.Configuration | null; + + /** + * desired_phase can currently only be updated on local-configuration runners, to + * toggle whether local runners are allowed for running environments in the + * organization. Set to: + * + * - ACTIVE to enable local runners. + * - INACTIVE to disable all local runners. Existing local runners and their + * environments will stop, and cannot be started again until the desired_phase is + * set to ACTIVE. Use this carefully, as it will affect all users in the + * organization who use local runners. + */ + desiredPhase?: RunnersAPI.RunnerPhase | null; + } + + export namespace Spec { + export interface Configuration { + /** + * auto_update indicates whether the runner should automatically update itself. + */ + autoUpdate?: boolean | null; + + /** + * devcontainer_image_cache_enabled controls whether the shared devcontainer build + * cache is enabled for this runner. + */ + devcontainerImageCacheEnabled?: boolean | null; + + /** + * log_level is the log level for the runner + */ + logLevel?: RunnersAPI.LogLevel | null; + + /** + * metrics contains configuration for the runner's metrics collection + */ + metrics?: Configuration.Metrics | null; + + /** + * The release channel the runner is on + */ + releaseChannel?: RunnersAPI.RunnerReleaseChannel | null; + } + + export namespace Configuration { + /** + * metrics contains configuration for the runner's metrics collection + */ + export interface Metrics { + /** + * enabled indicates whether the runner should collect metrics + */ + enabled?: boolean | null; + + /** + * password is the password to use for the metrics collector + */ + password?: string | null; + + /** + * url is the URL of the metrics collector + */ + url?: string | null; + + /** + * username is the username to use for the metrics collector + */ + username?: string | null; + } + } + } +} + +export interface RunnerListParams extends RunnersPageParams { + /** + * Body param: + */ + filter?: RunnerListParams.Filter; + + /** + * Body param: pagination contains the pagination options for listing runners + */ + pagination?: RunnerListParams.Pagination; +} + +export namespace RunnerListParams { + export interface Filter { + /** + * creator_ids filters the response to only runner created by specified users + */ + creatorIds?: Array<string>; + + /** + * kinds filters the response to only runners of the specified kinds + */ + kinds?: Array<RunnersAPI.RunnerKind>; + + /** + * providers filters the response to only runners of the specified providers + */ + providers?: Array<RunnersAPI.RunnerProvider>; + } + + /** + * pagination contains the pagination options for listing runners + */ + export interface Pagination { + /** + * Token for the next set of results that was returned as next_token of a + * PaginationResponse + */ + token?: string; + + /** + * Page size is the maximum number of results to retrieve per page. Defaults to 25. + * Maximum 100. + */ + pageSize?: number; + } +} + +export interface RunnerDeleteParams { + /** + * force indicates whether the runner should be deleted forcefully. When force + * deleting a Runner, all Environments on the runner are also force deleted and + * regular Runner lifecycle is not respected. Force deleting can result in data + * loss. + */ + force?: boolean; + + runnerId?: string; +} + +export interface RunnerCheckAuthenticationForHostParams { + host?: string; + + runnerId?: string; +} + +export interface RunnerCreateRunnerTokenParams { + runnerId?: string; +} + +export interface RunnerParseContextURLParams { + contextUrl?: string; + + runnerId?: string; +} + +Runners.Configurations = Configurations; +Runners.Policies = Policies; + +export declare namespace Runners { + export { + type LogLevel as LogLevel, + type MetricsConfiguration as MetricsConfiguration, + type Runner as Runner, + type RunnerCapability as RunnerCapability, + type RunnerConfiguration as RunnerConfiguration, + type RunnerKind as RunnerKind, + type RunnerPhase as RunnerPhase, + type RunnerProvider as RunnerProvider, + type RunnerReleaseChannel as RunnerReleaseChannel, + type RunnerSpec as RunnerSpec, + type RunnerStatus as RunnerStatus, + type RunnerCreateResponse as RunnerCreateResponse, + type RunnerRetrieveResponse as RunnerRetrieveResponse, + type RunnerUpdateResponse as RunnerUpdateResponse, + type RunnerDeleteResponse as RunnerDeleteResponse, + type RunnerCheckAuthenticationForHostResponse as RunnerCheckAuthenticationForHostResponse, + type RunnerCreateRunnerTokenResponse as RunnerCreateRunnerTokenResponse, + type RunnerParseContextURLResponse as RunnerParseContextURLResponse, + type RunnersRunnersPage as RunnersRunnersPage, + type RunnerCreateParams as RunnerCreateParams, + type RunnerRetrieveParams as RunnerRetrieveParams, + type RunnerUpdateParams as RunnerUpdateParams, + type RunnerListParams as RunnerListParams, + type RunnerDeleteParams as RunnerDeleteParams, + type RunnerCheckAuthenticationForHostParams as RunnerCheckAuthenticationForHostParams, + type RunnerCreateRunnerTokenParams as RunnerCreateRunnerTokenParams, + type RunnerParseContextURLParams as RunnerParseContextURLParams, + }; + + export { + Configurations as Configurations, + type EnvironmentClassValidationResult as EnvironmentClassValidationResult, + type FieldValidationError as FieldValidationError, + type ScmIntegrationValidationResult as ScmIntegrationValidationResult, + type ConfigurationValidateResponse as ConfigurationValidateResponse, + type ConfigurationValidateParams as ConfigurationValidateParams, + }; + + export { + Policies as Policies, + type RunnerPolicy as RunnerPolicy, + type RunnerRole as RunnerRole, + type PolicyCreateResponse as PolicyCreateResponse, + type PolicyUpdateResponse as PolicyUpdateResponse, + type PolicyDeleteResponse as PolicyDeleteResponse, + type RunnerPoliciesPoliciesPage as RunnerPoliciesPoliciesPage, + type PolicyCreateParams as PolicyCreateParams, + type PolicyUpdateParams as PolicyUpdateParams, + type PolicyListParams as PolicyListParams, + type PolicyDeleteParams as PolicyDeleteParams, + }; +} diff --git a/src/resources/secrets.ts b/src/resources/secrets.ts new file mode 100644 index 0000000..68c387d --- /dev/null +++ b/src/resources/secrets.ts @@ -0,0 +1,539 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../core/resource'; +import * as SecretsAPI from './secrets'; +import * as Shared from './shared'; +import { APIPromise } from '../core/api-promise'; +import { PagePromise, SecretsPage, type SecretsPageParams } from '../core/pagination'; +import { RequestOptions } from '../internal/request-options'; + +export class Secrets extends APIResource { + /** + * Creates a new secret for a project. + * + * Use this method to: + * + * - Store sensitive configuration values + * - Set up environment variables + * - Configure registry authentication + * - Add file-based secrets + * + * ### Examples + * + * - Create environment variable: + * + * Creates a secret that will be available as an environment variable. + * + * ```yaml + * name: "DATABASE_URL" + * projectId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + * value: "postgresql://user:pass@localhost:5432/db" + * environmentVariable: true + * ``` + * + * - Create file secret: + * + * Creates a secret that will be mounted as a file. + * + * ```yaml + * name: "SSH_KEY" + * projectId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + * value: "-----BEGIN RSA PRIVATE KEY-----\n..." + * filePath: "/home/gitpod/.ssh/id_rsa" + * ``` + * + * - Create registry auth: + * + * Creates credentials for private container registry. + * + * ```yaml + * name: "DOCKER_AUTH" + * projectId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + * value: "username:password" + * containerRegistryBasicAuthHost: "https://registry.example.com" + * ``` + */ + create(body: SecretCreateParams, options?: RequestOptions): APIPromise<SecretCreateResponse> { + return this._client.post('/gitpod.v1.SecretService/CreateSecret', { body, ...options }); + } + + /** + * Lists secrets + * + * Use this method to: + * + * - View all project secrets + * - View all user secrets + * + * ### Examples + * + * - List project secrets: + * + * Shows all secrets for a project. + * + * ```yaml + * filter: + * scope: + * projectId: "b0e12f6c-4c67-429d-a4a6-d9838b5da047" + * pagination: + * pageSize: 20 + * ``` + * + * - List user secrets: + * + * Shows all secrets for a user. + * + * ```yaml + * filter: + * scope: + * userId: "123e4567-e89b-12d3-a456-426614174000" + * pagination: + * pageSize: 20 + * ``` + */ + list(params: SecretListParams, options?: RequestOptions): PagePromise<SecretsSecretsPage, Secret> { + const { token, pageSize, ...body } = params; + return this._client.getAPIList('/gitpod.v1.SecretService/ListSecrets', SecretsPage<Secret>, { + query: { token, pageSize }, + body, + method: 'post', + ...options, + }); + } + + /** + * Deletes a secret permanently. + * + * Use this method to: + * + * - Remove unused secrets + * - Clean up old credentials + * + * ### Examples + * + * - Delete secret: + * + * Permanently removes a secret. + * + * ```yaml + * secretId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + * ``` + */ + delete(body: SecretDeleteParams, options?: RequestOptions): APIPromise<unknown> { + return this._client.post('/gitpod.v1.SecretService/DeleteSecret', { body, ...options }); + } + + /** + * Gets the value of a secret. Only available to environments that are authorized + * to access the secret. + * + * Use this method to: + * + * - Retrieve secret values + * - Access credentials + * + * ### Examples + * + * - Get secret value: + * + * Retrieves the value of a specific secret. + * + * ```yaml + * secretId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + * ``` + */ + getValue(body: SecretGetValueParams, options?: RequestOptions): APIPromise<SecretGetValueResponse> { + return this._client.post('/gitpod.v1.SecretService/GetSecretValue', { body, ...options }); + } + + /** + * Updates the value of an existing secret. + * + * Use this method to: + * + * - Rotate secret values + * - Update credentials + * + * ### Examples + * + * - Update secret value: + * + * Changes the value of an existing secret. + * + * ```yaml + * secretId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + * value: "new-secret-value" + * ``` + */ + updateValue(body: SecretUpdateValueParams, options?: RequestOptions): APIPromise<unknown> { + return this._client.post('/gitpod.v1.SecretService/UpdateSecretValue', { body, ...options }); + } +} + +export type SecretsSecretsPage = SecretsPage<Secret>; + +export interface Secret { + id?: string; + + /** + * secret will be mounted as a registry secret + */ + containerRegistryBasicAuthHost?: string; + + /** + * A Timestamp represents a point in time independent of any time zone or local + * calendar, encoded as a count of seconds and fractions of seconds at nanosecond + * resolution. The count is relative to an epoch at UTC midnight on January 1, + * 1970, in the proleptic Gregorian calendar which extends the Gregorian calendar + * backwards to year one. + * + * All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap + * second table is needed for interpretation, using a + * [24-hour linear smear](https://developers.google.com/time/smear). + * + * The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By + * restricting to that range, we ensure that we can convert to and from + * [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. + * + * # Examples + * + * Example 1: Compute Timestamp from POSIX `time()`. + * + * Timestamp timestamp; + * timestamp.set_seconds(time(NULL)); + * timestamp.set_nanos(0); + * + * Example 2: Compute Timestamp from POSIX `gettimeofday()`. + * + * struct timeval tv; + * gettimeofday(&tv, NULL); + * + * Timestamp timestamp; + * timestamp.set_seconds(tv.tv_sec); + * timestamp.set_nanos(tv.tv_usec * 1000); + * + * Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. + * + * FILETIME ft; + * GetSystemTimeAsFileTime(&ft); + * UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; + * + * // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z + * // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. + * Timestamp timestamp; + * timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); + * timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); + * + * Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. + * + * long millis = System.currentTimeMillis(); + * + * Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) + * .setNanos((int) ((millis % 1000) * 1000000)).build(); + * + * Example 5: Compute Timestamp from Java `Instant.now()`. + * + * Instant now = Instant.now(); + * + * Timestamp timestamp = + * Timestamp.newBuilder().setSeconds(now.getEpochSecond()) + * .setNanos(now.getNano()).build(); + * + * Example 6: Compute Timestamp from current time in Python. + * + * timestamp = Timestamp() + * timestamp.GetCurrentTime() + * + * # JSON Mapping + * + * In JSON format, the Timestamp type is encoded as a string in the + * [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the format is + * "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" where {year} is always + * expressed using four digits while {month}, {day}, {hour}, {min}, and {sec} are + * zero-padded to two digits each. The fractional seconds, which can go up to 9 + * digits (i.e. up to 1 nanosecond resolution), are optional. The "Z" suffix + * indicates the timezone ("UTC"); the timezone is required. A proto3 JSON + * serializer should always use UTC (as indicated by "Z") when printing the + * Timestamp type and a proto3 JSON parser should be able to accept both UTC and + * other timezones (as indicated by an offset). + * + * For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past 01:30 UTC on + * January 15, 2017. + * + * In JavaScript, one can convert a Date object to this format using the standard + * [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) + * method. In Python, a standard `datetime.datetime` object can be converted to + * this format using + * [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with the + * time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use the + * Joda Time's + * [`ISODateTimeFormat.dateTime()`](<http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime()>) + * to obtain a formatter capable of generating timestamps in this format. + */ + createdAt?: string; + + /** + * creator is the identity of the creator of the secret + */ + creator?: Shared.Subject; + + /** + * secret will be created as an Environment Variable with the same name as the + * secret + */ + environmentVariable?: boolean; + + /** + * absolute path to the file where the secret is mounted + */ + filePath?: string; + + /** + * Name of the secret for humans. + */ + name?: string; + + /** + * @deprecated The Project ID this Secret belongs to Deprecated: use scope instead + */ + projectId?: string; + + scope?: SecretScope; + + /** + * A Timestamp represents a point in time independent of any time zone or local + * calendar, encoded as a count of seconds and fractions of seconds at nanosecond + * resolution. The count is relative to an epoch at UTC midnight on January 1, + * 1970, in the proleptic Gregorian calendar which extends the Gregorian calendar + * backwards to year one. + * + * All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap + * second table is needed for interpretation, using a + * [24-hour linear smear](https://developers.google.com/time/smear). + * + * The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By + * restricting to that range, we ensure that we can convert to and from + * [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. + * + * # Examples + * + * Example 1: Compute Timestamp from POSIX `time()`. + * + * Timestamp timestamp; + * timestamp.set_seconds(time(NULL)); + * timestamp.set_nanos(0); + * + * Example 2: Compute Timestamp from POSIX `gettimeofday()`. + * + * struct timeval tv; + * gettimeofday(&tv, NULL); + * + * Timestamp timestamp; + * timestamp.set_seconds(tv.tv_sec); + * timestamp.set_nanos(tv.tv_usec * 1000); + * + * Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. + * + * FILETIME ft; + * GetSystemTimeAsFileTime(&ft); + * UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; + * + * // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z + * // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. + * Timestamp timestamp; + * timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); + * timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); + * + * Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. + * + * long millis = System.currentTimeMillis(); + * + * Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) + * .setNanos((int) ((millis % 1000) * 1000000)).build(); + * + * Example 5: Compute Timestamp from Java `Instant.now()`. + * + * Instant now = Instant.now(); + * + * Timestamp timestamp = + * Timestamp.newBuilder().setSeconds(now.getEpochSecond()) + * .setNanos(now.getNano()).build(); + * + * Example 6: Compute Timestamp from current time in Python. + * + * timestamp = Timestamp() + * timestamp.GetCurrentTime() + * + * # JSON Mapping + * + * In JSON format, the Timestamp type is encoded as a string in the + * [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the format is + * "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" where {year} is always + * expressed using four digits while {month}, {day}, {hour}, {min}, and {sec} are + * zero-padded to two digits each. The fractional seconds, which can go up to 9 + * digits (i.e. up to 1 nanosecond resolution), are optional. The "Z" suffix + * indicates the timezone ("UTC"); the timezone is required. A proto3 JSON + * serializer should always use UTC (as indicated by "Z") when printing the + * Timestamp type and a proto3 JSON parser should be able to accept both UTC and + * other timezones (as indicated by an offset). + * + * For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past 01:30 UTC on + * January 15, 2017. + * + * In JavaScript, one can convert a Date object to this format using the standard + * [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) + * method. In Python, a standard `datetime.datetime` object can be converted to + * this format using + * [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with the + * time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use the + * Joda Time's + * [`ISODateTimeFormat.dateTime()`](<http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime()>) + * to obtain a formatter capable of generating timestamps in this format. + */ + updatedAt?: string; +} + +export interface SecretScope { + /** + * project_id is the Project ID this Secret belongs to + */ + projectId?: string; + + /** + * user_id is the User ID this Secret belongs to + */ + userId?: string; +} + +export interface SecretCreateResponse { + secret?: Secret; +} + +export type SecretDeleteResponse = unknown; + +export interface SecretGetValueResponse { + value?: string; +} + +export type SecretUpdateValueResponse = unknown; + +export interface SecretCreateParams { + /** + * secret will be mounted as a docker config in the environment VM, mount will have + * the docker registry host + */ + containerRegistryBasicAuthHost?: string; + + /** + * secret will be created as an Environment Variable with the same name as the + * secret + */ + environmentVariable?: boolean; + + /** + * absolute path to the file where the secret is mounted value must be an absolute + * path (start with a /): + * + * ``` + * this.matches('^/(?:[^/]* /)*.*$') + * ``` + */ + filePath?: string; + + name?: string; + + /** + * @deprecated project_id is the ProjectID this Secret belongs to Deprecated: use + * scope instead + */ + projectId?: string; + + /** + * scope is the scope of the secret + */ + scope?: SecretScope; + + /** + * value is the plaintext value of the secret + */ + value?: string; +} + +export interface SecretListParams extends SecretsPageParams { + /** + * Body param: + */ + filter?: SecretListParams.Filter; + + /** + * Body param: pagination contains the pagination options for listing environments + */ + pagination?: SecretListParams.Pagination; +} + +export namespace SecretListParams { + export interface Filter { + /** + * @deprecated project_ids filters the response to only Secrets used by these + * Project IDs Deprecated: use scope instead. Values in project_ids will be + * ignored. + */ + projectIds?: Array<string>; + + /** + * scope is the scope of the secrets to list + */ + scope?: SecretsAPI.SecretScope; + } + + /** + * pagination contains the pagination options for listing environments + */ + export interface Pagination { + /** + * Token for the next set of results that was returned as next_token of a + * PaginationResponse + */ + token?: string; + + /** + * Page size is the maximum number of results to retrieve per page. Defaults to 25. + * Maximum 100. + */ + pageSize?: number; + } +} + +export interface SecretDeleteParams { + secretId?: string; +} + +export interface SecretGetValueParams { + secretId?: string; +} + +export interface SecretUpdateValueParams { + secretId?: string; + + /** + * value is the plaintext value of the secret + */ + value?: string; +} + +export declare namespace Secrets { + export { + type Secret as Secret, + type SecretScope as SecretScope, + type SecretCreateResponse as SecretCreateResponse, + type SecretDeleteResponse as SecretDeleteResponse, + type SecretGetValueResponse as SecretGetValueResponse, + type SecretUpdateValueResponse as SecretUpdateValueResponse, + type SecretsSecretsPage as SecretsSecretsPage, + type SecretCreateParams as SecretCreateParams, + type SecretListParams as SecretListParams, + type SecretDeleteParams as SecretDeleteParams, + type SecretGetValueParams as SecretGetValueParams, + type SecretUpdateValueParams as SecretUpdateValueParams, + }; +} diff --git a/src/resources/shared.ts b/src/resources/shared.ts new file mode 100644 index 0000000..d2f7c17 --- /dev/null +++ b/src/resources/shared.ts @@ -0,0 +1,355 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import * as Shared from './shared'; +import { EnvironmentClassesPage, TaskExecutionsPage, TasksPage } from '../core/pagination'; + +/** + * An AutomationTrigger represents a trigger for an automation action. The + * `post_environment_start` field indicates that the automation should be triggered + * after the environment has started. The `post_devcontainer_start` field indicates + * that the automation should be triggered after the dev container has started. + */ +export interface AutomationTrigger { + manual?: boolean; + + postDevcontainerStart?: boolean; + + postEnvironmentStart?: boolean; +} + +export interface EnvironmentClass { + /** + * id is the unique identifier of the environment class + */ + id: string; + + /** + * runner_id is the unique identifier of the runner the environment class belongs + * to + */ + runnerId: string; + + /** + * configuration describes the configuration of the environment class + */ + configuration?: Array<FieldValue>; + + /** + * description is a human readable description of the environment class + */ + description?: string; + + /** + * display_name is the human readable name of the environment class + */ + displayName?: string; + + /** + * enabled indicates whether the environment class can be used to create new + * environments. + */ + enabled?: boolean; +} + +/** + * The status code, which should be an enum value of + * [google.rpc.Code][google.rpc.Code]. + */ +export type ErrorCode = + | 'canceled' + | 'unknown' + | 'invalid_argument' + | 'deadline_exceeded' + | 'not_found' + | 'already_exists' + | 'permission_denied' + | 'resource_exhausted' + | 'failed_precondition' + | 'aborted' + | 'out_of_range' + | 'unimplemented' + | 'internal' + | 'unavailable' + | 'data_loss' + | 'unauthenticated'; + +export interface FieldValue { + key?: string; + + value?: string; +} + +export type OrganizationRole = + | 'ORGANIZATION_ROLE_UNSPECIFIED' + | 'ORGANIZATION_ROLE_ADMIN' + | 'ORGANIZATION_ROLE_MEMBER'; + +export type Principal = + | 'PRINCIPAL_UNSPECIFIED' + | 'PRINCIPAL_ACCOUNT' + | 'PRINCIPAL_USER' + | 'PRINCIPAL_RUNNER' + | 'PRINCIPAL_ENVIRONMENT' + | 'PRINCIPAL_SERVICE_ACCOUNT'; + +export interface RunsOn { + docker: RunsOn.Docker; +} + +export namespace RunsOn { + export interface Docker { + environment?: Array<string>; + + image?: string; + } +} + +export interface Subject { + /** + * id is the UUID of the subject + */ + id?: string; + + /** + * Principal is the principal of the subject + */ + principal?: Principal; +} + +export interface Task { + id: string; + + /** + * dependencies specifies the IDs of the automations this task depends on. + */ + dependsOn?: Array<string>; + + environmentId?: string; + + metadata?: TaskMetadata; + + spec?: TaskSpec; +} + +export interface TaskExecution { + id: string; + + metadata?: TaskExecutionMetadata; + + spec?: TaskExecutionSpec; + + status?: TaskExecutionStatus; +} + +export interface TaskExecutionMetadata { + /** + * completed_at is the time the task execution was done. + */ + completedAt?: string; + + /** + * created_at is the time the task was created. + */ + createdAt?: string; + + /** + * creator describes the principal who created/started the task run. + */ + creator?: Subject; + + /** + * environment_id is the ID of the environment in which the task run is executed. + */ + environmentId?: string; + + /** + * started_at is the time the task execution actually started to run. + */ + startedAt?: string; + + /** + * started_by describes the trigger that started the task execution. + */ + startedBy?: string; + + /** + * task_id is the ID of the main task being executed. + */ + taskId?: string; +} + +export type TaskExecutionPhase = + | 'TASK_EXECUTION_PHASE_UNSPECIFIED' + | 'TASK_EXECUTION_PHASE_PENDING' + | 'TASK_EXECUTION_PHASE_RUNNING' + | 'TASK_EXECUTION_PHASE_SUCCEEDED' + | 'TASK_EXECUTION_PHASE_FAILED' + | 'TASK_EXECUTION_PHASE_STOPPED'; + +export interface TaskExecutionSpec { + /** + * desired_phase is the phase the task execution should be in. Used to stop a + * running task execution early. + */ + desiredPhase?: TaskExecutionPhase; + + /** + * plan is a list of groups of steps. The steps in a group are executed + * concurrently, while the groups are executed sequentially. The order of the + * groups is the order in which they are executed. + */ + plan?: Array<TaskExecutionSpec.Plan>; +} + +export namespace TaskExecutionSpec { + export interface Plan { + steps?: Array<Plan.Step>; + } + + export namespace Plan { + export interface Step { + /** + * ID is the ID of the execution step + */ + id?: string; + + dependsOn?: Array<string>; + + label?: string; + + serviceId?: string; + + task?: Step.Task; + } + + export namespace Step { + export interface Task { + id?: string; + + spec?: Shared.TaskSpec; + } + } + } +} + +export interface TaskExecutionStatus { + /** + * failure_message summarises why the task execution failed to operate. If this is + * non-empty the task execution has failed to operate and will likely transition to + * a failed state. + */ + failureMessage?: string; + + /** + * log_url is the URL to the logs of the task's steps. If this is empty, the task + * either has no logs or has not yet started. + */ + logUrl?: string; + + /** + * the phase of a task execution represents the aggregated phase of all steps. + */ + phase?: TaskExecutionPhase; + + /** + * version of the status update. Task executions themselves are unversioned, but + * their status has different versions. The value of this field has no semantic + * meaning (e.g. don't interpret it as as a timestamp), but it can be used to + * impose a partial order. If a.status_version < b.status_version then a was the + * status before b. + */ + statusVersion?: string; + + /** + * steps provides the status for each individual step of the task execution. If a + * step is missing it has not yet started. + */ + steps?: Array<TaskExecutionStatus.Step>; +} + +export namespace TaskExecutionStatus { + export interface Step { + /** + * ID is the ID of the execution step + */ + id?: string; + + /** + * failure_message summarises why the step failed to operate. If this is non-empty + * the step has failed to operate and will likely transition to a failed state. + */ + failureMessage?: string; + + /** + * output contains the output of the task execution. setting an output field to + * empty string will unset it. + */ + output?: Record<string, string>; + + /** + * phase is the current phase of the execution step + */ + phase?: Shared.TaskExecutionPhase; + } +} + +export interface TaskMetadata { + /** + * created_at is the time the task was created. + */ + createdAt?: string; + + /** + * creator describes the principal who created the task. + */ + creator?: Subject; + + /** + * description is a user-facing description for the task. It can be used to provide + * context and documentation for the task. + */ + description?: string; + + /** + * name is a user-facing name for the task. Unlike the reference, this field is not + * unique, and not referenced by the system. This is a short descriptive name for + * the task. + */ + name?: string; + + /** + * reference is a user-facing identifier for the task which must be unique on the + * environment. It is used to express dependencies between tasks, and to identify + * the task in user interactions (e.g. the CLI). + */ + reference?: string; + + /** + * triggered_by is a list of trigger that start the task. + */ + triggeredBy?: Array<AutomationTrigger>; +} + +export interface TaskSpec { + /** + * command contains the command the task should execute + */ + command?: string; + + /** + * runs_on specifies the environment the task should run on. + */ + runsOn?: RunsOn; +} + +export type UserStatus = + | 'USER_STATUS_UNSPECIFIED' + | 'USER_STATUS_ACTIVE' + | 'USER_STATUS_SUSPENDED' + | 'USER_STATUS_LEFT'; + +export type TasksTasksPage = TasksPage<Task>; + +export type TaskExecutionsTaskExecutionsPage = TaskExecutionsPage<TaskExecution>; + +export type EnvironmentClassesEnvironmentClassesPage = EnvironmentClassesPage<EnvironmentClass>; diff --git a/src/resources/usage.ts b/src/resources/usage.ts new file mode 100644 index 0000000..9417a8f --- /dev/null +++ b/src/resources/usage.ts @@ -0,0 +1,159 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../core/resource'; +import { PagePromise, SessionsPage, type SessionsPageParams } from '../core/pagination'; +import { RequestOptions } from '../internal/request-options'; + +export class Usage extends APIResource { + /** + * Lists completed environment sessions within a specified date range. + * + * Returns a list of environment sessions that were completed within the specified + * date range. Currently running sessions are not included. + * + * Use this method to: + * + * - View environment sessions + * - Filter by project + * - Monitor session activity + * - Create custom usage reports + * + * ### Example + * + * ```yaml + * filter: + * projectId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + * dateRange: + * startTime: "2024-01-01T00:00:00Z" + * endTime: "2024-01-02T00:00:00Z" + * pagination: + * pageSize: 100 + * ``` + */ + listEnvironmentSessions( + params: UsageListEnvironmentSessionsParams, + options?: RequestOptions, + ): PagePromise<EnvironmentSessionsSessionsPage, EnvironmentSession> { + const { token, pageSize, ...body } = params; + return this._client.getAPIList( + '/gitpod.v1.UsageService/ListEnvironmentSessions', + SessionsPage<EnvironmentSession>, + { query: { token, pageSize }, body, method: 'post', ...options }, + ); + } +} + +export type EnvironmentSessionsSessionsPage = SessionsPage<EnvironmentSession>; + +export interface EnvironmentSession { + /** + * Environment session ID. + */ + id?: string; + + /** + * Time when the session was created. + */ + createdAt?: string; + + /** + * Environment class ID associated with the session. + */ + environmentClassId?: string; + + /** + * Environment ID associated with the session. + */ + environmentId?: string; + + /** + * Project ID associated with the session (if available). + */ + projectId?: string; + + /** + * Runner ID associated with the session. + */ + runnerId?: string; + + /** + * Time when the session was stopped. + */ + stoppedAt?: string; + + /** + * User ID that created the session. + */ + userId?: string; +} + +export interface UsageListEnvironmentSessionsParams extends SessionsPageParams { + /** + * Body param: Filter options. + */ + filter?: UsageListEnvironmentSessionsParams.Filter; + + /** + * Body param: Pagination options. + */ + pagination?: UsageListEnvironmentSessionsParams.Pagination; +} + +export namespace UsageListEnvironmentSessionsParams { + /** + * Filter options. + */ + export interface Filter { + /** + * Date range to query sessions within. + */ + dateRange: Filter.DateRange; + + /** + * Optional project ID to filter sessions by. + */ + projectId?: string; + } + + export namespace Filter { + /** + * Date range to query sessions within. + */ + export interface DateRange { + /** + * End time of the date range (exclusive). + */ + endTime: string; + + /** + * Start time of the date range (inclusive). + */ + startTime: string; + } + } + + /** + * Pagination options. + */ + export interface Pagination { + /** + * Token for the next set of results that was returned as next_token of a + * PaginationResponse + */ + token?: string; + + /** + * Page size is the maximum number of results to retrieve per page. Defaults to 25. + * Maximum 100. + */ + pageSize?: number; + } +} + +export declare namespace Usage { + export { + type EnvironmentSession as EnvironmentSession, + type EnvironmentSessionsSessionsPage as EnvironmentSessionsSessionsPage, + type UsageListEnvironmentSessionsParams as UsageListEnvironmentSessionsParams, + }; +} diff --git a/src/resources/users.ts b/src/resources/users.ts new file mode 100644 index 0000000..db908c7 --- /dev/null +++ b/src/resources/users.ts @@ -0,0 +1,3 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export * from './users/index'; diff --git a/src/resources/users/dotfiles.ts b/src/resources/users/dotfiles.ts new file mode 100644 index 0000000..7a69609 --- /dev/null +++ b/src/resources/users/dotfiles.ts @@ -0,0 +1,89 @@ +// 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 { RequestOptions } from '../../internal/request-options'; + +export class Dotfiles extends APIResource { + /** + * Gets the dotfiles for a user. + * + * Use this method to: + * + * - Retrieve user dotfiles + * + * ### Examples + * + * - Get dotfiles: + * + * Retrieves the dotfiles for the current user. + * + * ```yaml + * {} + * ``` + */ + get(body: DotfileGetParams, options?: RequestOptions): APIPromise<DotfileGetResponse> { + return this._client.post('/gitpod.v1.UserService/GetDotfilesConfiguration', { body, ...options }); + } + + /** + * Sets the dotfiles configuration for a user. + * + * Use this method to: + * + * - Configure user dotfiles + * - Update dotfiles settings + * + * ### Examples + * + * - Set dotfiles configuration: + * + * Sets the dotfiles configuration for the current user. + * + * ```yaml + * { "repository": "https://github.com/gitpod-io/dotfiles" } + * ``` + * + * - Remove dotfiles: + * + * Removes the dotfiles for the current user. + * + * ```yaml + * {} + * ``` + */ + set(body: DotfileSetParams, options?: RequestOptions): APIPromise<unknown> { + return this._client.post('/gitpod.v1.UserService/SetDotfilesConfiguration', { body, ...options }); + } +} + +export interface DotfilesConfiguration { + /** + * The URL of a dotfiles repository. + */ + repository?: string; +} + +export interface DotfileGetResponse { + dotfilesConfiguration: DotfilesConfiguration; +} + +export type DotfileSetResponse = unknown; + +export interface DotfileGetParams { + empty?: boolean; +} + +export interface DotfileSetParams { + repository?: string; +} + +export declare namespace Dotfiles { + export { + type DotfilesConfiguration as DotfilesConfiguration, + type DotfileGetResponse as DotfileGetResponse, + type DotfileSetResponse as DotfileSetResponse, + type DotfileGetParams as DotfileGetParams, + type DotfileSetParams as DotfileSetParams, + }; +} diff --git a/src/resources/users/index.ts b/src/resources/users/index.ts new file mode 100644 index 0000000..c91cbf0 --- /dev/null +++ b/src/resources/users/index.ts @@ -0,0 +1,28 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export { + Dotfiles, + type DotfilesConfiguration, + type DotfileGetResponse, + type DotfileSetResponse, + type DotfileGetParams, + type DotfileSetParams, +} from './dotfiles'; +export { + Pats, + type PersonalAccessToken, + type PatDeleteResponse, + type PatGetResponse, + type PatListParams, + type PatDeleteParams, + type PatGetParams, + type PersonalAccessTokensPersonalAccessTokensPage, +} from './pats'; +export { + Users, + type User, + type UserGetAuthenticatedUserResponse, + type UserSetSuspendedResponse, + type UserGetAuthenticatedUserParams, + type UserSetSuspendedParams, +} from './users'; diff --git a/src/resources/users/pats.ts b/src/resources/users/pats.ts new file mode 100644 index 0000000..6827d68 --- /dev/null +++ b/src/resources/users/pats.ts @@ -0,0 +1,443 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../../core/resource'; +import * as Shared from '../shared'; +import { APIPromise } from '../../core/api-promise'; +import { + PagePromise, + PersonalAccessTokensPage, + type PersonalAccessTokensPageParams, +} from '../../core/pagination'; +import { RequestOptions } from '../../internal/request-options'; + +export class Pats extends APIResource { + /** + * Lists personal access tokens with optional filtering. + * + * Use this method to: + * + * - View all active tokens + * - Audit token usage + * - Manage token lifecycle + * + * ### Examples + * + * - List user tokens: + * + * Shows all tokens for specific users. + * + * ```yaml + * filter: + * userIds: ["f53d2330-3795-4c5d-a1f3-453121af9c60"] + * pagination: + * pageSize: 20 + * ``` + */ + list( + params: PatListParams, + options?: RequestOptions, + ): PagePromise<PersonalAccessTokensPersonalAccessTokensPage, PersonalAccessToken> { + const { token, pageSize, ...body } = params; + return this._client.getAPIList( + '/gitpod.v1.UserService/ListPersonalAccessTokens', + PersonalAccessTokensPage<PersonalAccessToken>, + { query: { token, pageSize }, body, method: 'post', ...options }, + ); + } + + /** + * Deletes a personal access token. + * + * Use this method to: + * + * - Revoke token access + * - Remove unused tokens + * - Rotate credentials + * + * ### Examples + * + * - Delete token: + * + * Permanently revokes a token. + * + * ```yaml + * personalAccessTokenId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + * ``` + */ + delete(body: PatDeleteParams, options?: RequestOptions): APIPromise<unknown> { + return this._client.post('/gitpod.v1.UserService/DeletePersonalAccessToken', { body, ...options }); + } + + /** + * Gets details about a specific personal access token. + * + * Use this method to: + * + * - View token metadata + * - Check token expiration + * - Monitor token usage + * + * ### Examples + * + * - Get token details: + * + * Retrieves information about a specific token. + * + * ```yaml + * personalAccessTokenId: "d2c94c27-3b76-4a42-b88c-95a85e392c68" + * ``` + */ + get(body: PatGetParams, options?: RequestOptions): APIPromise<PatGetResponse> { + return this._client.post('/gitpod.v1.UserService/GetPersonalAccessToken', { body, ...options }); + } +} + +export type PersonalAccessTokensPersonalAccessTokensPage = PersonalAccessTokensPage<PersonalAccessToken>; + +export interface PersonalAccessToken { + id?: string; + + /** + * A Timestamp represents a point in time independent of any time zone or local + * calendar, encoded as a count of seconds and fractions of seconds at nanosecond + * resolution. The count is relative to an epoch at UTC midnight on January 1, + * 1970, in the proleptic Gregorian calendar which extends the Gregorian calendar + * backwards to year one. + * + * All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap + * second table is needed for interpretation, using a + * [24-hour linear smear](https://developers.google.com/time/smear). + * + * The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By + * restricting to that range, we ensure that we can convert to and from + * [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. + * + * # Examples + * + * Example 1: Compute Timestamp from POSIX `time()`. + * + * Timestamp timestamp; + * timestamp.set_seconds(time(NULL)); + * timestamp.set_nanos(0); + * + * Example 2: Compute Timestamp from POSIX `gettimeofday()`. + * + * struct timeval tv; + * gettimeofday(&tv, NULL); + * + * Timestamp timestamp; + * timestamp.set_seconds(tv.tv_sec); + * timestamp.set_nanos(tv.tv_usec * 1000); + * + * Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. + * + * FILETIME ft; + * GetSystemTimeAsFileTime(&ft); + * UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; + * + * // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z + * // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. + * Timestamp timestamp; + * timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); + * timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); + * + * Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. + * + * long millis = System.currentTimeMillis(); + * + * Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) + * .setNanos((int) ((millis % 1000) * 1000000)).build(); + * + * Example 5: Compute Timestamp from Java `Instant.now()`. + * + * Instant now = Instant.now(); + * + * Timestamp timestamp = + * Timestamp.newBuilder().setSeconds(now.getEpochSecond()) + * .setNanos(now.getNano()).build(); + * + * Example 6: Compute Timestamp from current time in Python. + * + * timestamp = Timestamp() + * timestamp.GetCurrentTime() + * + * # JSON Mapping + * + * In JSON format, the Timestamp type is encoded as a string in the + * [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the format is + * "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" where {year} is always + * expressed using four digits while {month}, {day}, {hour}, {min}, and {sec} are + * zero-padded to two digits each. The fractional seconds, which can go up to 9 + * digits (i.e. up to 1 nanosecond resolution), are optional. The "Z" suffix + * indicates the timezone ("UTC"); the timezone is required. A proto3 JSON + * serializer should always use UTC (as indicated by "Z") when printing the + * Timestamp type and a proto3 JSON parser should be able to accept both UTC and + * other timezones (as indicated by an offset). + * + * For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past 01:30 UTC on + * January 15, 2017. + * + * In JavaScript, one can convert a Date object to this format using the standard + * [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) + * method. In Python, a standard `datetime.datetime` object can be converted to + * this format using + * [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with the + * time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use the + * Joda Time's + * [`ISODateTimeFormat.dateTime()`](<http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime()>) + * to obtain a formatter capable of generating timestamps in this format. + */ + createdAt?: string; + + creator?: Shared.Subject; + + description?: string; + + /** + * A Timestamp represents a point in time independent of any time zone or local + * calendar, encoded as a count of seconds and fractions of seconds at nanosecond + * resolution. The count is relative to an epoch at UTC midnight on January 1, + * 1970, in the proleptic Gregorian calendar which extends the Gregorian calendar + * backwards to year one. + * + * All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap + * second table is needed for interpretation, using a + * [24-hour linear smear](https://developers.google.com/time/smear). + * + * The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By + * restricting to that range, we ensure that we can convert to and from + * [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. + * + * # Examples + * + * Example 1: Compute Timestamp from POSIX `time()`. + * + * Timestamp timestamp; + * timestamp.set_seconds(time(NULL)); + * timestamp.set_nanos(0); + * + * Example 2: Compute Timestamp from POSIX `gettimeofday()`. + * + * struct timeval tv; + * gettimeofday(&tv, NULL); + * + * Timestamp timestamp; + * timestamp.set_seconds(tv.tv_sec); + * timestamp.set_nanos(tv.tv_usec * 1000); + * + * Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. + * + * FILETIME ft; + * GetSystemTimeAsFileTime(&ft); + * UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; + * + * // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z + * // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. + * Timestamp timestamp; + * timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); + * timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); + * + * Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. + * + * long millis = System.currentTimeMillis(); + * + * Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) + * .setNanos((int) ((millis % 1000) * 1000000)).build(); + * + * Example 5: Compute Timestamp from Java `Instant.now()`. + * + * Instant now = Instant.now(); + * + * Timestamp timestamp = + * Timestamp.newBuilder().setSeconds(now.getEpochSecond()) + * .setNanos(now.getNano()).build(); + * + * Example 6: Compute Timestamp from current time in Python. + * + * timestamp = Timestamp() + * timestamp.GetCurrentTime() + * + * # JSON Mapping + * + * In JSON format, the Timestamp type is encoded as a string in the + * [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the format is + * "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" where {year} is always + * expressed using four digits while {month}, {day}, {hour}, {min}, and {sec} are + * zero-padded to two digits each. The fractional seconds, which can go up to 9 + * digits (i.e. up to 1 nanosecond resolution), are optional. The "Z" suffix + * indicates the timezone ("UTC"); the timezone is required. A proto3 JSON + * serializer should always use UTC (as indicated by "Z") when printing the + * Timestamp type and a proto3 JSON parser should be able to accept both UTC and + * other timezones (as indicated by an offset). + * + * For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past 01:30 UTC on + * January 15, 2017. + * + * In JavaScript, one can convert a Date object to this format using the standard + * [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) + * method. In Python, a standard `datetime.datetime` object can be converted to + * this format using + * [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with the + * time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use the + * Joda Time's + * [`ISODateTimeFormat.dateTime()`](<http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime()>) + * to obtain a formatter capable of generating timestamps in this format. + */ + expiresAt?: string; + + /** + * A Timestamp represents a point in time independent of any time zone or local + * calendar, encoded as a count of seconds and fractions of seconds at nanosecond + * resolution. The count is relative to an epoch at UTC midnight on January 1, + * 1970, in the proleptic Gregorian calendar which extends the Gregorian calendar + * backwards to year one. + * + * All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap + * second table is needed for interpretation, using a + * [24-hour linear smear](https://developers.google.com/time/smear). + * + * The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By + * restricting to that range, we ensure that we can convert to and from + * [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. + * + * # Examples + * + * Example 1: Compute Timestamp from POSIX `time()`. + * + * Timestamp timestamp; + * timestamp.set_seconds(time(NULL)); + * timestamp.set_nanos(0); + * + * Example 2: Compute Timestamp from POSIX `gettimeofday()`. + * + * struct timeval tv; + * gettimeofday(&tv, NULL); + * + * Timestamp timestamp; + * timestamp.set_seconds(tv.tv_sec); + * timestamp.set_nanos(tv.tv_usec * 1000); + * + * Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. + * + * FILETIME ft; + * GetSystemTimeAsFileTime(&ft); + * UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; + * + * // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z + * // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. + * Timestamp timestamp; + * timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); + * timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); + * + * Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. + * + * long millis = System.currentTimeMillis(); + * + * Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) + * .setNanos((int) ((millis % 1000) * 1000000)).build(); + * + * Example 5: Compute Timestamp from Java `Instant.now()`. + * + * Instant now = Instant.now(); + * + * Timestamp timestamp = + * Timestamp.newBuilder().setSeconds(now.getEpochSecond()) + * .setNanos(now.getNano()).build(); + * + * Example 6: Compute Timestamp from current time in Python. + * + * timestamp = Timestamp() + * timestamp.GetCurrentTime() + * + * # JSON Mapping + * + * In JSON format, the Timestamp type is encoded as a string in the + * [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the format is + * "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" where {year} is always + * expressed using four digits while {month}, {day}, {hour}, {min}, and {sec} are + * zero-padded to two digits each. The fractional seconds, which can go up to 9 + * digits (i.e. up to 1 nanosecond resolution), are optional. The "Z" suffix + * indicates the timezone ("UTC"); the timezone is required. A proto3 JSON + * serializer should always use UTC (as indicated by "Z") when printing the + * Timestamp type and a proto3 JSON parser should be able to accept both UTC and + * other timezones (as indicated by an offset). + * + * For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past 01:30 UTC on + * January 15, 2017. + * + * In JavaScript, one can convert a Date object to this format using the standard + * [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) + * method. In Python, a standard `datetime.datetime` object can be converted to + * this format using + * [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with the + * time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use the + * Joda Time's + * [`ISODateTimeFormat.dateTime()`](<http://joda-time.sourceforge.net/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime()>) + * to obtain a formatter capable of generating timestamps in this format. + */ + lastUsed?: string; + + userId?: string; +} + +export type PatDeleteResponse = unknown; + +export interface PatGetResponse { + pat: PersonalAccessToken; +} + +export interface PatListParams extends PersonalAccessTokensPageParams { + /** + * Body param: + */ + filter?: PatListParams.Filter; + + /** + * Body param: + */ + pagination?: PatListParams.Pagination; +} + +export namespace PatListParams { + export interface Filter { + /** + * creator_ids filters the response to only Environments created by specified + * members + */ + userIds?: Array<string>; + } + + export interface Pagination { + /** + * Token for the next set of results that was returned as next_token of a + * PaginationResponse + */ + token?: string; + + /** + * Page size is the maximum number of results to retrieve per page. Defaults to 25. + * Maximum 100. + */ + pageSize?: number; + } +} + +export interface PatDeleteParams { + personalAccessTokenId?: string; +} + +export interface PatGetParams { + personalAccessTokenId?: string; +} + +export declare namespace Pats { + export { + type PersonalAccessToken as PersonalAccessToken, + type PatDeleteResponse as PatDeleteResponse, + type PatGetResponse as PatGetResponse, + type PersonalAccessTokensPersonalAccessTokensPage as PersonalAccessTokensPersonalAccessTokensPage, + type PatListParams as PatListParams, + type PatDeleteParams as PatDeleteParams, + type PatGetParams as PatGetParams, + }; +} diff --git a/src/resources/users/users.ts b/src/resources/users/users.ts new file mode 100644 index 0000000..07f8eca --- /dev/null +++ b/src/resources/users/users.ts @@ -0,0 +1,174 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIResource } from '../../core/resource'; +import * as Shared from '../shared'; +import * as DotfilesAPI from './dotfiles'; +import { + DotfileGetParams, + DotfileGetResponse, + DotfileSetParams, + DotfileSetResponse, + Dotfiles, + DotfilesConfiguration, +} from './dotfiles'; +import * as PatsAPI from './pats'; +import { + PatDeleteParams, + PatDeleteResponse, + PatGetParams, + PatGetResponse, + PatListParams, + Pats, + PersonalAccessToken, + PersonalAccessTokensPersonalAccessTokensPage, +} from './pats'; +import { APIPromise } from '../../core/api-promise'; +import { RequestOptions } from '../../internal/request-options'; + +export class Users extends APIResource { + dotfiles: DotfilesAPI.Dotfiles = new DotfilesAPI.Dotfiles(this._client); + pats: PatsAPI.Pats = new PatsAPI.Pats(this._client); + + /** + * Gets information about the currently authenticated user. + * + * Use this method to: + * + * - Get user profile information + * - Check authentication status + * - Retrieve user settings + * - Verify account details + * + * ### Examples + * + * - Get current user: + * + * Retrieves details about the authenticated user. + * + * ```yaml + * {} + * ``` + */ + getAuthenticatedUser( + body: UserGetAuthenticatedUserParams, + options?: RequestOptions, + ): APIPromise<UserGetAuthenticatedUserResponse> { + return this._client.post('/gitpod.v1.UserService/GetAuthenticatedUser', { body, ...options }); + } + + /** + * Sets whether a user account is suspended. + * + * Use this method to: + * + * - Suspend problematic users + * - Reactivate suspended accounts + * - Manage user access + * + * ### Examples + * + * - Suspend user: + * + * Suspends a user account. + * + * ```yaml + * userId: "f53d2330-3795-4c5d-a1f3-453121af9c60" + * suspended: true + * ``` + * + * - Reactivate user: + * + * Removes suspension from a user account. + * + * ```yaml + * userId: "f53d2330-3795-4c5d-a1f3-453121af9c60" + * suspended: false + * ``` + */ + setSuspended(body: UserSetSuspendedParams, options?: RequestOptions): APIPromise<unknown> { + return this._client.post('/gitpod.v1.UserService/SetSuspended', { body, ...options }); + } +} + +export interface User { + /** + * id is a UUID of the user + */ + id: string; + + /** + * avatar_url is a link to the user avatar + */ + avatarUrl?: string; + + /** + * created_at is the creation time + */ + createdAt?: string; + + /** + * name is the full name of the user + */ + name?: string; + + /** + * organization_id is the id of the organization this account is owned by. + * + * +optional if not set, this account is owned by the installation. + */ + organizationId?: string; + + /** + * status is the status the user is in + */ + status?: Shared.UserStatus; +} + +export interface UserGetAuthenticatedUserResponse { + user: User; +} + +export type UserSetSuspendedResponse = unknown; + +export interface UserGetAuthenticatedUserParams { + empty?: boolean; +} + +export interface UserSetSuspendedParams { + suspended?: boolean; + + userId?: string; +} + +Users.Dotfiles = Dotfiles; +Users.Pats = Pats; + +export declare namespace Users { + export { + type User as User, + type UserGetAuthenticatedUserResponse as UserGetAuthenticatedUserResponse, + type UserSetSuspendedResponse as UserSetSuspendedResponse, + type UserGetAuthenticatedUserParams as UserGetAuthenticatedUserParams, + type UserSetSuspendedParams as UserSetSuspendedParams, + }; + + export { + Dotfiles as Dotfiles, + type DotfilesConfiguration as DotfilesConfiguration, + type DotfileGetResponse as DotfileGetResponse, + type DotfileSetResponse as DotfileSetResponse, + type DotfileGetParams as DotfileGetParams, + type DotfileSetParams as DotfileSetParams, + }; + + export { + Pats as Pats, + type PersonalAccessToken as PersonalAccessToken, + type PatDeleteResponse as PatDeleteResponse, + type PatGetResponse as PatGetResponse, + type PersonalAccessTokensPersonalAccessTokensPage as PersonalAccessTokensPersonalAccessTokensPage, + type PatListParams as PatListParams, + type PatDeleteParams as PatDeleteParams, + type PatGetParams as PatGetParams, + }; +} diff --git a/src/uploads.ts b/src/uploads.ts new file mode 100644 index 0000000..b2ef647 --- /dev/null +++ b/src/uploads.ts @@ -0,0 +1,2 @@ +/** @deprecated Import from ./core/uploads instead */ +export * from './core/uploads'; diff --git a/src/version.ts b/src/version.ts new file mode 100644 index 0000000..1f5d158 --- /dev/null +++ b/src/version.ts @@ -0,0 +1 @@ +export const VERSION = '0.5.0'; // x-release-please-version diff --git a/tests/api-resources/accounts.test.ts b/tests/api-resources/accounts.test.ts new file mode 100644 index 0000000..85aed19 --- /dev/null +++ b/tests/api-resources/accounts.test.ts @@ -0,0 +1,71 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import Gitpod from '@gitpod/sdk'; + +const client = new Gitpod({ + bearerToken: 'My Bearer Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +describe('resource accounts', () => { + // skipped: tests are disabled for the time being + test.skip('retrieve', async () => { + const responsePromise = client.accounts.retrieve({}); + 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('delete: only required params', async () => { + const responsePromise = client.accounts.delete({ accountId: 'f53d2330-3795-4c5d-a1f3-453121af9c60' }); + 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('delete: required and optional params', async () => { + const response = await client.accounts.delete({ accountId: 'f53d2330-3795-4c5d-a1f3-453121af9c60' }); + }); + + // skipped: tests are disabled for the time being + test.skip('getSSOLoginURL: only required params', async () => { + const responsePromise = client.accounts.getSSOLoginURL({ email: 'user@company.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('getSSOLoginURL: required and optional params', async () => { + const response = await client.accounts.getSSOLoginURL({ + email: 'user@company.com', + returnTo: 'https://example.com', + }); + }); + + // skipped: tests are disabled for the time being + test.skip('listLoginProviders', async () => { + const responsePromise = client.accounts.listLoginProviders({}); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); +}); diff --git a/tests/api-resources/editors.test.ts b/tests/api-resources/editors.test.ts new file mode 100644 index 0000000..e3e3a7c --- /dev/null +++ b/tests/api-resources/editors.test.ts @@ -0,0 +1,64 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import Gitpod from '@gitpod/sdk'; + +const client = new Gitpod({ + bearerToken: 'My Bearer Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +describe('resource editors', () => { + // skipped: tests are disabled for the time being + test.skip('retrieve: only required params', async () => { + const responsePromise = client.editors.retrieve({ id: 'd2c94c27-3b76-4a42-b88c-95a85e392c68' }); + 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('retrieve: required and optional params', async () => { + const response = await client.editors.retrieve({ id: 'd2c94c27-3b76-4a42-b88c-95a85e392c68' }); + }); + + // skipped: tests are disabled for the time being + test.skip('list', async () => { + const responsePromise = client.editors.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('resolveURL: only required params', async () => { + const responsePromise = client.editors.resolveURL({ + editorId: 'd2c94c27-3b76-4a42-b88c-95a85e392c68', + environmentId: '07e03a28-65a5-4d98-b532-8ea67b188048', + organizationId: 'b0e12f6c-4c67-429d-a4a6-d9838b5da047', + }); + 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('resolveURL: required and optional params', async () => { + const response = await client.editors.resolveURL({ + editorId: 'd2c94c27-3b76-4a42-b88c-95a85e392c68', + environmentId: '07e03a28-65a5-4d98-b532-8ea67b188048', + organizationId: 'b0e12f6c-4c67-429d-a4a6-d9838b5da047', + }); + }); +}); diff --git a/tests/api-resources/environments/automations/automations.test.ts b/tests/api-resources/environments/automations/automations.test.ts new file mode 100644 index 0000000..45b054d --- /dev/null +++ b/tests/api-resources/environments/automations/automations.test.ts @@ -0,0 +1,22 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import Gitpod from '@gitpod/sdk'; + +const client = new Gitpod({ + bearerToken: 'My Bearer Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +describe('resource automations', () => { + // skipped: tests are disabled for the time being + test.skip('upsert', async () => { + const responsePromise = client.environments.automations.upsert({}); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); +}); diff --git a/tests/api-resources/environments/automations/services.test.ts b/tests/api-resources/environments/automations/services.test.ts new file mode 100644 index 0000000..9f01bea --- /dev/null +++ b/tests/api-resources/environments/automations/services.test.ts @@ -0,0 +1,94 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import Gitpod from '@gitpod/sdk'; + +const client = new Gitpod({ + bearerToken: 'My Bearer Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +describe('resource services', () => { + // skipped: tests are disabled for the time being + test.skip('create', async () => { + const responsePromise = client.environments.automations.services.create({}); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + // skipped: tests are disabled for the time being + test.skip('retrieve', async () => { + const responsePromise = client.environments.automations.services.retrieve({}); + 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', async () => { + const responsePromise = client.environments.automations.services.update({}); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + // skipped: tests are disabled for the time being + test.skip('list', async () => { + const responsePromise = client.environments.automations.services.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('delete', async () => { + const responsePromise = client.environments.automations.services.delete({}); + 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('start', async () => { + const responsePromise = client.environments.automations.services.start({}); + 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('stop', async () => { + const responsePromise = client.environments.automations.services.stop({}); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); +}); diff --git a/tests/api-resources/environments/automations/tasks/executions.test.ts b/tests/api-resources/environments/automations/tasks/executions.test.ts new file mode 100644 index 0000000..7c8f4e4 --- /dev/null +++ b/tests/api-resources/environments/automations/tasks/executions.test.ts @@ -0,0 +1,46 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import Gitpod from '@gitpod/sdk'; + +const client = new Gitpod({ + bearerToken: 'My Bearer Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +describe('resource executions', () => { + // skipped: tests are disabled for the time being + test.skip('retrieve', async () => { + const responsePromise = client.environments.automations.tasks.executions.retrieve({}); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + // skipped: tests are disabled for the time being + test.skip('list', async () => { + const responsePromise = client.environments.automations.tasks.executions.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('stop', async () => { + const responsePromise = client.environments.automations.tasks.executions.stop({}); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); +}); diff --git a/tests/api-resources/environments/automations/tasks/tasks.test.ts b/tests/api-resources/environments/automations/tasks/tasks.test.ts new file mode 100644 index 0000000..a928d7f --- /dev/null +++ b/tests/api-resources/environments/automations/tasks/tasks.test.ts @@ -0,0 +1,82 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import Gitpod from '@gitpod/sdk'; + +const client = new Gitpod({ + bearerToken: 'My Bearer Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +describe('resource tasks', () => { + // skipped: tests are disabled for the time being + test.skip('create', async () => { + const responsePromise = client.environments.automations.tasks.create({}); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + // skipped: tests are disabled for the time being + test.skip('retrieve', async () => { + const responsePromise = client.environments.automations.tasks.retrieve({}); + 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', async () => { + const responsePromise = client.environments.automations.tasks.update({}); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + // skipped: tests are disabled for the time being + test.skip('list', async () => { + const responsePromise = client.environments.automations.tasks.list({}); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + // skipped: tests are disabled for the time being + test.skip('delete', async () => { + const responsePromise = client.environments.automations.tasks.delete({}); + 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('start', async () => { + const responsePromise = client.environments.automations.tasks.start({}); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); +}); diff --git a/tests/api-resources/environments/classes.test.ts b/tests/api-resources/environments/classes.test.ts new file mode 100644 index 0000000..da2c482 --- /dev/null +++ b/tests/api-resources/environments/classes.test.ts @@ -0,0 +1,22 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import Gitpod from '@gitpod/sdk'; + +const client = new Gitpod({ + bearerToken: 'My Bearer Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +describe('resource classes', () => { + // skipped: tests are disabled for the time being + test.skip('list', async () => { + const responsePromise = client.environments.classes.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); + }); +}); diff --git a/tests/api-resources/environments/environments.test.ts b/tests/api-resources/environments/environments.test.ts new file mode 100644 index 0000000..aaf1efc --- /dev/null +++ b/tests/api-resources/environments/environments.test.ts @@ -0,0 +1,160 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import Gitpod from '@gitpod/sdk'; + +const client = new Gitpod({ + bearerToken: 'My Bearer Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +describe('resource environments', () => { + // skipped: tests are disabled for the time being + test.skip('create', async () => { + const responsePromise = client.environments.create({}); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + // skipped: tests are disabled for the time being + test.skip('retrieve: only required params', async () => { + const responsePromise = client.environments.retrieve({ + environmentId: '07e03a28-65a5-4d98-b532-8ea67b188048', + }); + 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('retrieve: required and optional params', async () => { + const response = await client.environments.retrieve({ + environmentId: '07e03a28-65a5-4d98-b532-8ea67b188048', + }); + }); + + // skipped: tests are disabled for the time being + test.skip('update', async () => { + const responsePromise = client.environments.update({}); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + // skipped: tests are disabled for the time being + test.skip('list', async () => { + const responsePromise = client.environments.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('delete', async () => { + const responsePromise = client.environments.delete({}); + 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('createEnvironmentToken: only required params', async () => { + const responsePromise = client.environments.createEnvironmentToken({ + environmentId: '07e03a28-65a5-4d98-b532-8ea67b188048', + }); + 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('createEnvironmentToken: required and optional params', async () => { + const response = await client.environments.createEnvironmentToken({ + environmentId: '07e03a28-65a5-4d98-b532-8ea67b188048', + }); + }); + + // skipped: tests are disabled for the time being + test.skip('createFromProject', async () => { + const responsePromise = client.environments.createFromProject({}); + 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('createLogsToken', async () => { + const responsePromise = client.environments.createLogsToken({}); + 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('markActive', async () => { + const responsePromise = client.environments.markActive({}); + 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('start', async () => { + const responsePromise = client.environments.start({}); + 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('stop', async () => { + const responsePromise = client.environments.stop({}); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); +}); diff --git a/tests/api-resources/events.test.ts b/tests/api-resources/events.test.ts new file mode 100644 index 0000000..d556b72 --- /dev/null +++ b/tests/api-resources/events.test.ts @@ -0,0 +1,34 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import Gitpod from '@gitpod/sdk'; + +const client = new Gitpod({ + bearerToken: 'My Bearer Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +describe('resource events', () => { + // skipped: tests are disabled for the time being + test.skip('list', async () => { + const responsePromise = client.events.list({}); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + // Prism doesn't support JSONL responses yet + test.skip('watch', async () => { + const responsePromise = client.events.watch({}); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); +}); diff --git a/tests/api-resources/groups.test.ts b/tests/api-resources/groups.test.ts new file mode 100644 index 0000000..dcc3e5b --- /dev/null +++ b/tests/api-resources/groups.test.ts @@ -0,0 +1,22 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import Gitpod from '@gitpod/sdk'; + +const client = new Gitpod({ + bearerToken: 'My Bearer Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +describe('resource groups', () => { + // skipped: tests are disabled for the time being + test.skip('list', async () => { + const responsePromise = client.groups.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); + }); +}); diff --git a/tests/api-resources/identity.test.ts b/tests/api-resources/identity.test.ts new file mode 100644 index 0000000..985ccfb --- /dev/null +++ b/tests/api-resources/identity.test.ts @@ -0,0 +1,46 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import Gitpod from '@gitpod/sdk'; + +const client = new Gitpod({ + bearerToken: 'My Bearer Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +describe('resource identity', () => { + // skipped: tests are disabled for the time being + test.skip('exchangeToken', async () => { + const responsePromise = client.identity.exchangeToken({}); + 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('getAuthenticatedIdentity', async () => { + const responsePromise = client.identity.getAuthenticatedIdentity({}); + 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('getIDToken', async () => { + const responsePromise = client.identity.getIDToken({}); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); +}); diff --git a/tests/api-resources/organizations/domain-verifications.test.ts b/tests/api-resources/organizations/domain-verifications.test.ts new file mode 100644 index 0000000..aa5b7e4 --- /dev/null +++ b/tests/api-resources/organizations/domain-verifications.test.ts @@ -0,0 +1,120 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import Gitpod from '@gitpod/sdk'; + +const client = new Gitpod({ + bearerToken: 'My Bearer Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +describe('resource domainVerifications', () => { + // skipped: tests are disabled for the time being + test.skip('create: only required params', async () => { + const responsePromise = client.organizations.domainVerifications.create({ + domain: 'acme-corp.com', + organizationId: 'b0e12f6c-4c67-429d-a4a6-d9838b5da047', + }); + 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.organizations.domainVerifications.create({ + domain: 'acme-corp.com', + organizationId: 'b0e12f6c-4c67-429d-a4a6-d9838b5da047', + }); + }); + + // skipped: tests are disabled for the time being + test.skip('retrieve: only required params', async () => { + const responsePromise = client.organizations.domainVerifications.retrieve({ + domainVerificationId: 'd2c94c27-3b76-4a42-b88c-95a85e392c68', + }); + 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('retrieve: required and optional params', async () => { + const response = await client.organizations.domainVerifications.retrieve({ + domainVerificationId: 'd2c94c27-3b76-4a42-b88c-95a85e392c68', + }); + }); + + // skipped: tests are disabled for the time being + test.skip('list: only required params', async () => { + const responsePromise = client.organizations.domainVerifications.list({ + organizationId: 'b0e12f6c-4c67-429d-a4a6-d9838b5da047', + }); + 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: required and optional params', async () => { + const response = await client.organizations.domainVerifications.list({ + organizationId: 'b0e12f6c-4c67-429d-a4a6-d9838b5da047', + token: 'token', + pageSize: 0, + pagination: { token: 'token', pageSize: 20 }, + }); + }); + + // skipped: tests are disabled for the time being + test.skip('delete: only required params', async () => { + const responsePromise = client.organizations.domainVerifications.delete({ + domainVerificationId: 'd2c94c27-3b76-4a42-b88c-95a85e392c68', + }); + 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('delete: required and optional params', async () => { + const response = await client.organizations.domainVerifications.delete({ + domainVerificationId: 'd2c94c27-3b76-4a42-b88c-95a85e392c68', + }); + }); + + // skipped: tests are disabled for the time being + test.skip('verify: only required params', async () => { + const responsePromise = client.organizations.domainVerifications.verify({ + domainVerificationId: 'd2c94c27-3b76-4a42-b88c-95a85e392c68', + }); + 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('verify: required and optional params', async () => { + const response = await client.organizations.domainVerifications.verify({ + domainVerificationId: 'd2c94c27-3b76-4a42-b88c-95a85e392c68', + }); + }); +}); diff --git a/tests/api-resources/organizations/invites.test.ts b/tests/api-resources/organizations/invites.test.ts new file mode 100644 index 0000000..8d2dbb3 --- /dev/null +++ b/tests/api-resources/organizations/invites.test.ts @@ -0,0 +1,73 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import Gitpod from '@gitpod/sdk'; + +const client = new Gitpod({ + bearerToken: 'My Bearer Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +describe('resource invites', () => { + // skipped: tests are disabled for the time being + test.skip('create: only required params', async () => { + const responsePromise = client.organizations.invites.create({ + organizationId: 'b0e12f6c-4c67-429d-a4a6-d9838b5da047', + }); + 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.organizations.invites.create({ + organizationId: 'b0e12f6c-4c67-429d-a4a6-d9838b5da047', + }); + }); + + // skipped: tests are disabled for the time being + test.skip('retrieve: only required params', async () => { + const responsePromise = client.organizations.invites.retrieve({ + organizationId: '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', + }); + 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('retrieve: required and optional params', async () => { + const response = await client.organizations.invites.retrieve({ + organizationId: '182bd5e5-6e1a-4fe4-a799-aa6d9a6ab26e', + }); + }); + + // skipped: tests are disabled for the time being + test.skip('getSummary: only required params', async () => { + const responsePromise = client.organizations.invites.getSummary({ + inviteId: 'd2c94c27-3b76-4a42-b88c-95a85e392c68', + }); + 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('getSummary: required and optional params', async () => { + const response = await client.organizations.invites.getSummary({ + inviteId: 'd2c94c27-3b76-4a42-b88c-95a85e392c68', + }); + }); +}); diff --git a/tests/api-resources/organizations/organizations.test.ts b/tests/api-resources/organizations/organizations.test.ts new file mode 100644 index 0000000..09fc8b7 --- /dev/null +++ b/tests/api-resources/organizations/organizations.test.ts @@ -0,0 +1,173 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import Gitpod from '@gitpod/sdk'; + +const client = new Gitpod({ + bearerToken: 'My Bearer Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +describe('resource organizations', () => { + // skipped: tests are disabled for the time being + test.skip('create: only required params', async () => { + const responsePromise = client.organizations.create({ name: 'Acme Corp Engineering' }); + 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.organizations.create({ + name: 'Acme Corp Engineering', + inviteAccountsWithMatchingDomain: true, + joinOrganization: true, + }); + }); + + // skipped: tests are disabled for the time being + test.skip('retrieve: only required params', async () => { + const responsePromise = client.organizations.retrieve({ + organizationId: 'b0e12f6c-4c67-429d-a4a6-d9838b5da047', + }); + 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('retrieve: required and optional params', async () => { + const response = await client.organizations.retrieve({ + organizationId: 'b0e12f6c-4c67-429d-a4a6-d9838b5da047', + }); + }); + + // skipped: tests are disabled for the time being + test.skip('update: only required params', async () => { + const responsePromise = client.organizations.update({ + organizationId: 'b0e12f6c-4c67-429d-a4a6-d9838b5da047', + }); + 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.organizations.update({ + organizationId: 'b0e12f6c-4c67-429d-a4a6-d9838b5da047', + inviteDomains: { domains: ['sfN2.l.iJR-BU.u9JV9.a.m.o2D-4b-Jd.0Z-kX.L.n.S.f.UKbxB'] }, + name: 'name', + }); + }); + + // skipped: tests are disabled for the time being + test.skip('delete: only required params', async () => { + const responsePromise = client.organizations.delete({ + organizationId: 'b0e12f6c-4c67-429d-a4a6-d9838b5da047', + }); + 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('delete: required and optional params', async () => { + const response = await client.organizations.delete({ + organizationId: 'b0e12f6c-4c67-429d-a4a6-d9838b5da047', + }); + }); + + // skipped: tests are disabled for the time being + test.skip('join', async () => { + const responsePromise = client.organizations.join({}); + 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('leave: only required params', async () => { + const responsePromise = client.organizations.leave({ userId: 'f53d2330-3795-4c5d-a1f3-453121af9c60' }); + 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('leave: required and optional params', async () => { + const response = await client.organizations.leave({ userId: 'f53d2330-3795-4c5d-a1f3-453121af9c60' }); + }); + + // skipped: tests are disabled for the time being + test.skip('listMembers: only required params', async () => { + const responsePromise = client.organizations.listMembers({ + organizationId: 'b0e12f6c-4c67-429d-a4a6-d9838b5da047', + }); + 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('listMembers: required and optional params', async () => { + const response = await client.organizations.listMembers({ + organizationId: 'b0e12f6c-4c67-429d-a4a6-d9838b5da047', + token: 'token', + pageSize: 0, + pagination: { token: 'token', pageSize: 20 }, + }); + }); + + // skipped: tests are disabled for the time being + test.skip('setRole: only required params', async () => { + const responsePromise = client.organizations.setRole({ + organizationId: 'b0e12f6c-4c67-429d-a4a6-d9838b5da047', + userId: 'f53d2330-3795-4c5d-a1f3-453121af9c60', + }); + 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('setRole: required and optional params', async () => { + const response = await client.organizations.setRole({ + organizationId: 'b0e12f6c-4c67-429d-a4a6-d9838b5da047', + userId: 'f53d2330-3795-4c5d-a1f3-453121af9c60', + role: 'ORGANIZATION_ROLE_MEMBER', + }); + }); +}); diff --git a/tests/api-resources/organizations/policies.test.ts b/tests/api-resources/organizations/policies.test.ts new file mode 100644 index 0000000..a0aba22 --- /dev/null +++ b/tests/api-resources/organizations/policies.test.ts @@ -0,0 +1,61 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import Gitpod from '@gitpod/sdk'; + +const client = new Gitpod({ + bearerToken: 'My Bearer Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +describe('resource policies', () => { + // skipped: tests are disabled for the time being + test.skip('retrieve: only required params', async () => { + const responsePromise = client.organizations.policies.retrieve({ + organizationId: 'b0e12f6c-4c67-429d-a4a6-d9838b5da047', + }); + 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('retrieve: required and optional params', async () => { + const response = await client.organizations.policies.retrieve({ + organizationId: 'b0e12f6c-4c67-429d-a4a6-d9838b5da047', + }); + }); + + // skipped: tests are disabled for the time being + test.skip('update: only required params', async () => { + const responsePromise = client.organizations.policies.update({ + organizationId: 'b0e12f6c-4c67-429d-a4a6-d9838b5da047', + }); + 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.organizations.policies.update({ + organizationId: 'b0e12f6c-4c67-429d-a4a6-d9838b5da047', + allowedEditorIds: ['string'], + allowLocalRunners: true, + defaultEditorId: 'defaultEditorId', + defaultEnvironmentImage: 'defaultEnvironmentImage', + maximumEnvironmentsPerUser: '20', + maximumEnvironmentTimeout: '3600s', + maximumRunningEnvironmentsPerUser: '5', + membersCreateProjects: true, + membersRequireProjects: true, + }); + }); +}); diff --git a/tests/api-resources/organizations/sso-configurations.test.ts b/tests/api-resources/organizations/sso-configurations.test.ts new file mode 100644 index 0000000..06c24ee --- /dev/null +++ b/tests/api-resources/organizations/sso-configurations.test.ts @@ -0,0 +1,132 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import Gitpod from '@gitpod/sdk'; + +const client = new Gitpod({ + bearerToken: 'My Bearer Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +describe('resource ssoConfigurations', () => { + // skipped: tests are disabled for the time being + test.skip('create: only required params', async () => { + const responsePromise = client.organizations.ssoConfigurations.create({ + clientId: '012345678-abcdefghijklmnopqrstuvwxyz.apps.googleusercontent.com', + clientSecret: 'GOCSPX-abcdefghijklmnopqrstuvwxyz123456', + emailDomain: 'acme-corp.com', + issuerUrl: 'https://accounts.google.com', + organizationId: 'b0e12f6c-4c67-429d-a4a6-d9838b5da047', + }); + 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.organizations.ssoConfigurations.create({ + clientId: '012345678-abcdefghijklmnopqrstuvwxyz.apps.googleusercontent.com', + clientSecret: 'GOCSPX-abcdefghijklmnopqrstuvwxyz123456', + emailDomain: 'acme-corp.com', + issuerUrl: 'https://accounts.google.com', + organizationId: 'b0e12f6c-4c67-429d-a4a6-d9838b5da047', + }); + }); + + // skipped: tests are disabled for the time being + test.skip('retrieve: only required params', async () => { + const responsePromise = client.organizations.ssoConfigurations.retrieve({ + ssoConfigurationId: 'd2c94c27-3b76-4a42-b88c-95a85e392c68', + }); + 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('retrieve: required and optional params', async () => { + const response = await client.organizations.ssoConfigurations.retrieve({ + ssoConfigurationId: 'd2c94c27-3b76-4a42-b88c-95a85e392c68', + }); + }); + + // skipped: tests are disabled for the time being + test.skip('update: only required params', async () => { + const responsePromise = client.organizations.ssoConfigurations.update({ + ssoConfigurationId: 'd2c94c27-3b76-4a42-b88c-95a85e392c68', + }); + 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.organizations.ssoConfigurations.update({ + ssoConfigurationId: 'd2c94c27-3b76-4a42-b88c-95a85e392c68', + claims: { foo: 'string' }, + clientId: 'new-client-id', + clientSecret: 'new-client-secret', + emailDomain: 'xxxx', + issuerUrl: 'https://example.com', + state: 'SSO_CONFIGURATION_STATE_UNSPECIFIED', + }); + }); + + // skipped: tests are disabled for the time being + test.skip('list: only required params', async () => { + const responsePromise = client.organizations.ssoConfigurations.list({ + organizationId: 'b0e12f6c-4c67-429d-a4a6-d9838b5da047', + }); + 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: required and optional params', async () => { + const response = await client.organizations.ssoConfigurations.list({ + organizationId: 'b0e12f6c-4c67-429d-a4a6-d9838b5da047', + token: 'token', + pageSize: 0, + pagination: { token: 'token', pageSize: 20 }, + }); + }); + + // skipped: tests are disabled for the time being + test.skip('delete: only required params', async () => { + const responsePromise = client.organizations.ssoConfigurations.delete({ + ssoConfigurationId: 'd2c94c27-3b76-4a42-b88c-95a85e392c68', + }); + 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('delete: required and optional params', async () => { + const response = await client.organizations.ssoConfigurations.delete({ + ssoConfigurationId: 'd2c94c27-3b76-4a42-b88c-95a85e392c68', + }); + }); +}); diff --git a/tests/api-resources/projects/policies.test.ts b/tests/api-resources/projects/policies.test.ts new file mode 100644 index 0000000..2b99235 --- /dev/null +++ b/tests/api-resources/projects/policies.test.ts @@ -0,0 +1,58 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import Gitpod from '@gitpod/sdk'; + +const client = new Gitpod({ + bearerToken: 'My Bearer Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +describe('resource policies', () => { + // skipped: tests are disabled for the time being + test.skip('create', async () => { + const responsePromise = client.projects.policies.create({}); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + // skipped: tests are disabled for the time being + test.skip('update', async () => { + const responsePromise = client.projects.policies.update({}); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + // skipped: tests are disabled for the time being + test.skip('list', async () => { + const responsePromise = client.projects.policies.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('delete', async () => { + const responsePromise = client.projects.policies.delete({}); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); +}); diff --git a/tests/api-resources/projects/projects.test.ts b/tests/api-resources/projects/projects.test.ts new file mode 100644 index 0000000..b30ee89 --- /dev/null +++ b/tests/api-resources/projects/projects.test.ts @@ -0,0 +1,107 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import Gitpod from '@gitpod/sdk'; + +const client = new Gitpod({ + bearerToken: 'My Bearer Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +describe('resource projects', () => { + // skipped: tests are disabled for the time being + test.skip('create: only required params', async () => { + const responsePromise = client.projects.create({ environmentClass: {}, initializer: {} }); + 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.projects.create({ + environmentClass: { environmentClassId: 'd2c94c27-3b76-4a42-b88c-95a85e392c68', localRunner: true }, + initializer: { + specs: [ + { + contextUrl: { url: 'https://example.com' }, + git: { + checkoutLocation: 'checkoutLocation', + cloneTarget: 'cloneTarget', + remoteUri: 'https://github.com/org/repo', + targetMode: 'CLONE_TARGET_MODE_UNSPECIFIED', + upstreamRemoteUri: 'upstreamRemoteUri', + }, + }, + ], + }, + automationsFilePath: 'automationsFilePath', + devcontainerFilePath: 'devcontainerFilePath', + name: 'Web Application', + technicalDescription: 'technicalDescription', + }); + }); + + // skipped: tests are disabled for the time being + test.skip('retrieve', async () => { + const responsePromise = client.projects.retrieve({}); + 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', async () => { + const responsePromise = client.projects.update({}); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + // skipped: tests are disabled for the time being + test.skip('list', async () => { + const responsePromise = client.projects.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('delete', async () => { + const responsePromise = client.projects.delete({}); + 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('createFromEnvironment', async () => { + const responsePromise = client.projects.createFromEnvironment({}); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); +}); diff --git a/tests/api-resources/runners/configurations/configurations.test.ts b/tests/api-resources/runners/configurations/configurations.test.ts new file mode 100644 index 0000000..c23963f --- /dev/null +++ b/tests/api-resources/runners/configurations/configurations.test.ts @@ -0,0 +1,22 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import Gitpod from '@gitpod/sdk'; + +const client = new Gitpod({ + bearerToken: 'My Bearer Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +describe('resource configurations', () => { + // skipped: tests are disabled for the time being + test.skip('validate', async () => { + const responsePromise = client.runners.configurations.validate({}); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); +}); diff --git a/tests/api-resources/runners/configurations/environment-classes.test.ts b/tests/api-resources/runners/configurations/environment-classes.test.ts new file mode 100644 index 0000000..f7b49dd --- /dev/null +++ b/tests/api-resources/runners/configurations/environment-classes.test.ts @@ -0,0 +1,58 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import Gitpod from '@gitpod/sdk'; + +const client = new Gitpod({ + bearerToken: 'My Bearer Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +describe('resource environmentClasses', () => { + // skipped: tests are disabled for the time being + test.skip('create', async () => { + const responsePromise = client.runners.configurations.environmentClasses.create({}); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + // skipped: tests are disabled for the time being + test.skip('retrieve', async () => { + const responsePromise = client.runners.configurations.environmentClasses.retrieve({}); + 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', async () => { + const responsePromise = client.runners.configurations.environmentClasses.update({}); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + // skipped: tests are disabled for the time being + test.skip('list', async () => { + const responsePromise = client.runners.configurations.environmentClasses.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); + }); +}); diff --git a/tests/api-resources/runners/configurations/host-authentication-tokens.test.ts b/tests/api-resources/runners/configurations/host-authentication-tokens.test.ts new file mode 100644 index 0000000..a5c4a50 --- /dev/null +++ b/tests/api-resources/runners/configurations/host-authentication-tokens.test.ts @@ -0,0 +1,70 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import Gitpod from '@gitpod/sdk'; + +const client = new Gitpod({ + bearerToken: 'My Bearer Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +describe('resource hostAuthenticationTokens', () => { + // skipped: tests are disabled for the time being + test.skip('create', async () => { + const responsePromise = client.runners.configurations.hostAuthenticationTokens.create({}); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + // skipped: tests are disabled for the time being + test.skip('retrieve', async () => { + const responsePromise = client.runners.configurations.hostAuthenticationTokens.retrieve({}); + 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', async () => { + const responsePromise = client.runners.configurations.hostAuthenticationTokens.update({}); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + // skipped: tests are disabled for the time being + test.skip('list', async () => { + const responsePromise = client.runners.configurations.hostAuthenticationTokens.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('delete', async () => { + const responsePromise = client.runners.configurations.hostAuthenticationTokens.delete({}); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); +}); diff --git a/tests/api-resources/runners/configurations/schema.test.ts b/tests/api-resources/runners/configurations/schema.test.ts new file mode 100644 index 0000000..5315e4a --- /dev/null +++ b/tests/api-resources/runners/configurations/schema.test.ts @@ -0,0 +1,22 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import Gitpod from '@gitpod/sdk'; + +const client = new Gitpod({ + bearerToken: 'My Bearer Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +describe('resource schema', () => { + // skipped: tests are disabled for the time being + test.skip('retrieve', async () => { + const responsePromise = client.runners.configurations.schema.retrieve({}); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); +}); diff --git a/tests/api-resources/runners/configurations/scm-integrations.test.ts b/tests/api-resources/runners/configurations/scm-integrations.test.ts new file mode 100644 index 0000000..6b59259 --- /dev/null +++ b/tests/api-resources/runners/configurations/scm-integrations.test.ts @@ -0,0 +1,70 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import Gitpod from '@gitpod/sdk'; + +const client = new Gitpod({ + bearerToken: 'My Bearer Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +describe('resource scmIntegrations', () => { + // skipped: tests are disabled for the time being + test.skip('create', async () => { + const responsePromise = client.runners.configurations.scmIntegrations.create({}); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + // skipped: tests are disabled for the time being + test.skip('retrieve', async () => { + const responsePromise = client.runners.configurations.scmIntegrations.retrieve({}); + 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', async () => { + const responsePromise = client.runners.configurations.scmIntegrations.update({}); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + // skipped: tests are disabled for the time being + test.skip('list', async () => { + const responsePromise = client.runners.configurations.scmIntegrations.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('delete', async () => { + const responsePromise = client.runners.configurations.scmIntegrations.delete({}); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); +}); diff --git a/tests/api-resources/runners/policies.test.ts b/tests/api-resources/runners/policies.test.ts new file mode 100644 index 0000000..533b1d8 --- /dev/null +++ b/tests/api-resources/runners/policies.test.ts @@ -0,0 +1,58 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import Gitpod from '@gitpod/sdk'; + +const client = new Gitpod({ + bearerToken: 'My Bearer Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +describe('resource policies', () => { + // skipped: tests are disabled for the time being + test.skip('create', async () => { + const responsePromise = client.runners.policies.create({}); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + // skipped: tests are disabled for the time being + test.skip('update', async () => { + const responsePromise = client.runners.policies.update({}); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + // skipped: tests are disabled for the time being + test.skip('list', async () => { + const responsePromise = client.runners.policies.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('delete', async () => { + const responsePromise = client.runners.policies.delete({}); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); +}); diff --git a/tests/api-resources/runners/runners.test.ts b/tests/api-resources/runners/runners.test.ts new file mode 100644 index 0000000..8a6573a --- /dev/null +++ b/tests/api-resources/runners/runners.test.ts @@ -0,0 +1,106 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import Gitpod from '@gitpod/sdk'; + +const client = new Gitpod({ + bearerToken: 'My Bearer Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +describe('resource runners', () => { + // skipped: tests are disabled for the time being + test.skip('create', async () => { + const responsePromise = client.runners.create({}); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + // skipped: tests are disabled for the time being + test.skip('retrieve', async () => { + const responsePromise = client.runners.retrieve({}); + 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', async () => { + const responsePromise = client.runners.update({}); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + // skipped: tests are disabled for the time being + test.skip('list', async () => { + const responsePromise = client.runners.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('delete', async () => { + const responsePromise = client.runners.delete({}); + 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('checkAuthenticationForHost', async () => { + const responsePromise = client.runners.checkAuthenticationForHost({}); + 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('createRunnerToken', async () => { + const responsePromise = client.runners.createRunnerToken({}); + 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('parseContextURL', async () => { + const responsePromise = client.runners.parseContextURL({}); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); +}); diff --git a/tests/api-resources/secrets.test.ts b/tests/api-resources/secrets.test.ts new file mode 100644 index 0000000..fc3c4c7 --- /dev/null +++ b/tests/api-resources/secrets.test.ts @@ -0,0 +1,70 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import Gitpod from '@gitpod/sdk'; + +const client = new Gitpod({ + bearerToken: 'My Bearer Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +describe('resource secrets', () => { + // skipped: tests are disabled for the time being + test.skip('create', async () => { + const responsePromise = client.secrets.create({}); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); + + // skipped: tests are disabled for the time being + test.skip('list', async () => { + const responsePromise = client.secrets.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('delete', async () => { + const responsePromise = client.secrets.delete({}); + 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('getValue', async () => { + const responsePromise = client.secrets.getValue({}); + 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('updateValue', async () => { + const responsePromise = client.secrets.updateValue({}); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); +}); diff --git a/tests/api-resources/usage.test.ts b/tests/api-resources/usage.test.ts new file mode 100644 index 0000000..1d2b3dc --- /dev/null +++ b/tests/api-resources/usage.test.ts @@ -0,0 +1,22 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import Gitpod from '@gitpod/sdk'; + +const client = new Gitpod({ + bearerToken: 'My Bearer Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +describe('resource usage', () => { + // skipped: tests are disabled for the time being + test.skip('listEnvironmentSessions', async () => { + const responsePromise = client.usage.listEnvironmentSessions({}); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); +}); diff --git a/tests/api-resources/users/dotfiles.test.ts b/tests/api-resources/users/dotfiles.test.ts new file mode 100644 index 0000000..5694cb1 --- /dev/null +++ b/tests/api-resources/users/dotfiles.test.ts @@ -0,0 +1,34 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import Gitpod from '@gitpod/sdk'; + +const client = new Gitpod({ + bearerToken: 'My Bearer Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +describe('resource dotfiles', () => { + // skipped: tests are disabled for the time being + test.skip('get', async () => { + const responsePromise = client.users.dotfiles.get({}); + 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('set', async () => { + const responsePromise = client.users.dotfiles.set({}); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); +}); diff --git a/tests/api-resources/users/pats.test.ts b/tests/api-resources/users/pats.test.ts new file mode 100644 index 0000000..cb8544c --- /dev/null +++ b/tests/api-resources/users/pats.test.ts @@ -0,0 +1,46 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import Gitpod from '@gitpod/sdk'; + +const client = new Gitpod({ + bearerToken: 'My Bearer Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +describe('resource pats', () => { + // skipped: tests are disabled for the time being + test.skip('list', async () => { + const responsePromise = client.users.pats.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('delete', async () => { + const responsePromise = client.users.pats.delete({}); + 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('get', async () => { + const responsePromise = client.users.pats.get({}); + const rawResponse = await responsePromise.asResponse(); + expect(rawResponse).toBeInstanceOf(Response); + const response = await responsePromise; + expect(response).not.toBeInstanceOf(Response); + const dataAndResponse = await responsePromise.withResponse(); + expect(dataAndResponse.data).toBe(response); + expect(dataAndResponse.response).toBe(rawResponse); + }); +}); diff --git a/tests/api-resources/users/users.test.ts b/tests/api-resources/users/users.test.ts new file mode 100644 index 0000000..4131035 --- /dev/null +++ b/tests/api-resources/users/users.test.ts @@ -0,0 +1,34 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import Gitpod from '@gitpod/sdk'; + +const client = new Gitpod({ + bearerToken: 'My Bearer Token', + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', +}); + +describe('resource users', () => { + // skipped: tests are disabled for the time being + test.skip('getAuthenticatedUser', async () => { + const responsePromise = client.users.getAuthenticatedUser({}); + 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('setSuspended', async () => { + const responsePromise = client.users.setSuspended({}); + 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 new file mode 100644 index 0000000..7ed687c --- /dev/null +++ b/tests/base64.test.ts @@ -0,0 +1,80 @@ +import { fromBase64, toBase64 } from '@gitpod/sdk/internal/utils/base64'; + +describe.each(['Buffer', 'atob'])('with %s', (mode) => { + let originalBuffer: BufferConstructor; + beforeAll(() => { + if (mode === 'atob') { + originalBuffer = globalThis.Buffer; + // @ts-expect-error Can't assign undefined to BufferConstructor + delete globalThis.Buffer; + } + }); + afterAll(() => { + if (mode === 'atob') { + globalThis.Buffer = originalBuffer; + } + }); + test('toBase64', () => { + const testCases = [ + { + input: 'hello world', + expected: 'aGVsbG8gd29ybGQ=', + }, + { + input: new Uint8Array([104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100]), + expected: 'aGVsbG8gd29ybGQ=', + }, + { + input: undefined, + expected: '', + }, + { + input: new Uint8Array([ + 229, 102, 215, 230, 65, 22, 46, 87, 243, 176, 99, 99, 31, 174, 8, 242, 83, 142, 169, 64, 122, 123, + 193, 71, + ]), + expected: '5WbX5kEWLlfzsGNjH64I8lOOqUB6e8FH', + }, + { + input: '✓', + expected: '4pyT', + }, + { + input: new Uint8Array([226, 156, 147]), + expected: '4pyT', + }, + ]; + + testCases.forEach(({ input, expected }) => { + expect(toBase64(input)).toBe(expected); + }); + }); + + test('fromBase64', () => { + const testCases = [ + { + input: 'aGVsbG8gd29ybGQ=', + expected: new Uint8Array([104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100]), + }, + { + input: '', + expected: new Uint8Array([]), + }, + { + input: '5WbX5kEWLlfzsGNjH64I8lOOqUB6e8FH', + expected: new Uint8Array([ + 229, 102, 215, 230, 65, 22, 46, 87, 243, 176, 99, 99, 31, 174, 8, 242, 83, 142, 169, 64, 122, 123, + 193, 71, + ]), + }, + { + input: '4pyT', + expected: new Uint8Array([226, 156, 147]), + }, + ]; + + testCases.forEach(({ input, expected }) => { + expect(fromBase64(input)).toEqual(expected); + }); + }); +}); diff --git a/tests/buildHeaders.test.ts b/tests/buildHeaders.test.ts new file mode 100644 index 0000000..f2e10fe --- /dev/null +++ b/tests/buildHeaders.test.ts @@ -0,0 +1,88 @@ +import { inspect } from 'node:util'; +import { buildHeaders, type HeadersLike, type NullableHeaders } from '@gitpod/sdk/internal/headers'; + +function inspectNullableHeaders(headers: NullableHeaders) { + return `NullableHeaders {${[ + ...[...headers.values.entries()].map(([name, value]) => ` ${inspect(name)}: ${inspect(value)}`), + ...[...headers.nulls].map((name) => ` ${inspect(name)}: null`), + ].join(', ')} }`; +} + +describe('buildHeaders', () => { + const cases: [HeadersLike[], string][] = [ + [[new Headers({ 'content-type': 'text/plain' })], `NullableHeaders { 'content-type': 'text/plain' }`], + [ + [ + { + 'content-type': 'text/plain', + }, + { + 'Content-Type': undefined, + }, + ], + `NullableHeaders { 'content-type': 'text/plain' }`, + ], + [ + [ + { + 'content-type': 'text/plain', + }, + { + 'Content-Type': null, + }, + ], + `NullableHeaders { 'content-type': null }`, + ], + [ + [ + { + cookie: 'name1=value1', + Cookie: 'name2=value2', + }, + ], + `NullableHeaders { 'cookie': 'name2=value2' }`, + ], + [ + [ + { + cookie: 'name1=value1', + Cookie: undefined, + }, + ], + `NullableHeaders { 'cookie': 'name1=value1' }`, + ], + [ + [ + { + cookie: ['name1=value1', 'name2=value2'], + }, + ], + `NullableHeaders { 'cookie': 'name1=value1; name2=value2' }`, + ], + [ + [ + { + 'x-foo': ['name1=value1', 'name2=value2'], + }, + ], + `NullableHeaders { 'x-foo': 'name1=value1, name2=value2' }`, + ], + [ + [ + [ + ['cookie', 'name1=value1'], + ['cookie', 'name2=value2'], + ['Cookie', 'name3=value3'], + ], + ], + `NullableHeaders { 'cookie': 'name1=value1; name2=value2; name3=value3' }`, + ], + [[undefined], `NullableHeaders { }`], + [[null], `NullableHeaders { }`], + ]; + for (const [input, expected] of cases) { + test(expected, () => { + expect(inspectNullableHeaders(buildHeaders(input))).toEqual(expected); + }); + } +}); diff --git a/tests/form.test.ts b/tests/form.test.ts new file mode 100644 index 0000000..cb575ba --- /dev/null +++ b/tests/form.test.ts @@ -0,0 +1,85 @@ +import { multipartFormRequestOptions, createForm } from '@gitpod/sdk/internal/uploads'; +import { toFile } from '@gitpod/sdk/core/uploads'; + +describe('form data validation', () => { + test('valid values do not error', async () => { + await multipartFormRequestOptions( + { + body: { + foo: 'foo', + string: 1, + bool: true, + file: await toFile(Buffer.from('some-content')), + blob: new Blob(['Some content'], { type: 'text/plain' }), + }, + }, + fetch, + ); + }); + + test('null', async () => { + await expect(() => + multipartFormRequestOptions( + { + body: { + null: null, + }, + }, + fetch, + ), + ).rejects.toThrow(TypeError); + }); + + test('undefined is stripped', async () => { + const form = await createForm( + { + foo: undefined, + bar: 'baz', + }, + fetch, + ); + expect(form.has('foo')).toBe(false); + expect(form.get('bar')).toBe('baz'); + }); + + test('nested undefined property is stripped', async () => { + const form = await createForm( + { + bar: { + baz: undefined, + }, + }, + fetch, + ); + expect(Array.from(form.entries())).toEqual([]); + + const form2 = await createForm( + { + bar: { + foo: 'string', + baz: undefined, + }, + }, + fetch, + ); + expect(Array.from(form2.entries())).toEqual([['bar[foo]', 'string']]); + }); + + test('nested undefined array item is stripped', async () => { + const form = await createForm( + { + bar: [undefined, undefined], + }, + fetch, + ); + expect(Array.from(form.entries())).toEqual([]); + + const form2 = await createForm( + { + bar: [undefined, 'foo'], + }, + fetch, + ); + expect(Array.from(form2.entries())).toEqual([['bar[]', 'foo']]); + }); +}); diff --git a/tests/index.test.ts b/tests/index.test.ts new file mode 100644 index 0000000..afe3fed --- /dev/null +++ b/tests/index.test.ts @@ -0,0 +1,642 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { APIPromise } from '@gitpod/sdk/core/api-promise'; + +import util from 'node:util'; +import Gitpod from '@gitpod/sdk'; +import { APIUserAbortError } from '@gitpod/sdk'; +const defaultFetch = fetch; + +describe('instantiate client', () => { + const env = process.env; + + beforeEach(() => { + jest.resetModules(); + process.env = { ...env }; + }); + + afterEach(() => { + process.env = env; + }); + + describe('defaultHeaders', () => { + const client = new Gitpod({ + baseURL: 'http://localhost:5000/', + defaultHeaders: { 'X-My-Default-Header': '2' }, + bearerToken: 'My Bearer Token', + }); + + test('they are used in the request', () => { + const { req } = client.buildRequest({ path: '/foo', method: 'post' }); + expect(req.headers.get('x-my-default-header')).toEqual('2'); + }); + + test('can ignore `undefined` and leave the default', () => { + const { req } = client.buildRequest({ + path: '/foo', + method: 'post', + headers: { 'X-My-Default-Header': undefined }, + }); + expect(req.headers.get('x-my-default-header')).toEqual('2'); + }); + + test('can be removed with `null`', () => { + const { req } = client.buildRequest({ + path: '/foo', + method: 'post', + headers: { 'X-My-Default-Header': null }, + }); + expect(req.headers.has('x-my-default-header')).toBe(false); + }); + }); + describe('logging', () => { + const env = process.env; + + beforeEach(() => { + process.env = { ...env }; + process.env['GITPOD_LOG'] = undefined; + }); + + afterEach(() => { + process.env = env; + }); + + const forceAPIResponseForClient = async (client: Gitpod) => { + await new APIPromise( + client, + Promise.resolve({ + response: new Response(), + controller: new AbortController(), + requestLogID: 'log_000000', + retryOfRequestLogID: undefined, + startTime: Date.now(), + options: { + method: 'get', + path: '/', + }, + }), + ); + }; + + test('debug logs when log level is debug', async () => { + const debugMock = jest.fn(); + const logger = { + debug: debugMock, + info: jest.fn(), + warn: jest.fn(), + error: jest.fn(), + }; + + const client = new Gitpod({ logger: logger, logLevel: 'debug', bearerToken: 'My Bearer Token' }); + + await forceAPIResponseForClient(client); + expect(debugMock).toHaveBeenCalled(); + }); + + test('default logLevel is warn', async () => { + const client = new Gitpod({ bearerToken: 'My Bearer Token' }); + expect(client.logLevel).toBe('warn'); + }); + + test('debug logs are skipped when log level is info', async () => { + const debugMock = jest.fn(); + const logger = { + debug: debugMock, + info: jest.fn(), + warn: jest.fn(), + error: jest.fn(), + }; + + const client = new Gitpod({ logger: logger, logLevel: 'info', bearerToken: 'My Bearer Token' }); + + await forceAPIResponseForClient(client); + expect(debugMock).not.toHaveBeenCalled(); + }); + + test('debug logs happen with debug env var', async () => { + const debugMock = jest.fn(); + const logger = { + debug: debugMock, + info: jest.fn(), + warn: jest.fn(), + error: jest.fn(), + }; + + process.env['GITPOD_LOG'] = 'debug'; + const client = new Gitpod({ logger: logger, bearerToken: 'My Bearer Token' }); + expect(client.logLevel).toBe('debug'); + + await forceAPIResponseForClient(client); + expect(debugMock).toHaveBeenCalled(); + }); + + test('warn when env var level is invalid', async () => { + const warnMock = jest.fn(); + const logger = { + debug: jest.fn(), + info: jest.fn(), + warn: warnMock, + error: jest.fn(), + }; + + process.env['GITPOD_LOG'] = 'not a log level'; + const client = new Gitpod({ logger: logger, bearerToken: 'My Bearer Token' }); + expect(client.logLevel).toBe('warn'); + expect(warnMock).toHaveBeenCalledWith( + 'process.env[\'GITPOD_LOG\'] was set to "not a log level", expected one of ["off","error","warn","info","debug"]', + ); + }); + + test('client log level overrides env var', async () => { + const debugMock = jest.fn(); + const logger = { + debug: debugMock, + info: jest.fn(), + warn: jest.fn(), + error: jest.fn(), + }; + + process.env['GITPOD_LOG'] = 'debug'; + const client = new Gitpod({ logger: logger, logLevel: 'off', bearerToken: 'My Bearer Token' }); + + await forceAPIResponseForClient(client); + expect(debugMock).not.toHaveBeenCalled(); + }); + + test('no warning logged for invalid env var level + valid client level', async () => { + const warnMock = jest.fn(); + const logger = { + debug: jest.fn(), + info: jest.fn(), + warn: warnMock, + error: jest.fn(), + }; + + process.env['GITPOD_LOG'] = 'not a log level'; + const client = new Gitpod({ logger: logger, logLevel: 'debug', bearerToken: 'My Bearer Token' }); + expect(client.logLevel).toBe('debug'); + expect(warnMock).not.toHaveBeenCalled(); + }); + }); + + describe('defaultQuery', () => { + test('with null query params given', () => { + const client = new Gitpod({ + baseURL: 'http://localhost:5000/', + defaultQuery: { apiVersion: 'foo' }, + bearerToken: 'My Bearer Token', + }); + expect(client.buildURL('/foo', null)).toEqual('http://localhost:5000/foo?apiVersion=foo'); + }); + + test('multiple default query params', () => { + const client = new Gitpod({ + baseURL: 'http://localhost:5000/', + defaultQuery: { apiVersion: 'foo', hello: 'world' }, + bearerToken: 'My Bearer Token', + }); + expect(client.buildURL('/foo', null)).toEqual('http://localhost:5000/foo?apiVersion=foo&hello=world'); + }); + + test('overriding with `undefined`', () => { + const client = new Gitpod({ + baseURL: 'http://localhost:5000/', + defaultQuery: { hello: 'world' }, + bearerToken: 'My Bearer Token', + }); + expect(client.buildURL('/foo', { hello: undefined })).toEqual('http://localhost:5000/foo'); + }); + }); + + test('custom fetch', async () => { + const client = new Gitpod({ + baseURL: 'http://localhost:5000/', + bearerToken: 'My Bearer Token', + fetch: (url) => { + return Promise.resolve( + new Response(JSON.stringify({ url, custom: true }), { + headers: { 'Content-Type': 'application/json' }, + }), + ); + }, + }); + + const response = await client.get('/foo'); + expect(response).toEqual({ url: 'http://localhost:5000/foo', custom: true }); + }); + + test('explicit global fetch', async () => { + // make sure the global fetch type is assignable to our Fetch type + const client = new Gitpod({ + baseURL: 'http://localhost:5000/', + bearerToken: 'My Bearer Token', + fetch: defaultFetch, + }); + }); + + test('custom signal', async () => { + const client = new Gitpod({ + baseURL: process.env['TEST_API_BASE_URL'] ?? 'http://127.0.0.1:4010', + bearerToken: 'My Bearer Token', + fetch: (...args) => { + return new Promise((resolve, reject) => + setTimeout( + () => + defaultFetch(...args) + .then(resolve) + .catch(reject), + 300, + ), + ); + }, + }); + + const controller = new AbortController(); + setTimeout(() => controller.abort(), 200); + + const spy = jest.spyOn(client, 'request'); + + await expect(client.get('/foo', { signal: controller.signal })).rejects.toThrowError(APIUserAbortError); + expect(spy).toHaveBeenCalledTimes(1); + }); + + test('normalized method', async () => { + let capturedRequest: RequestInit | undefined; + const testFetch = async (url: string | URL | Request, init: RequestInit = {}): Promise<Response> => { + capturedRequest = init; + return new Response(JSON.stringify({}), { headers: { 'Content-Type': 'application/json' } }); + }; + + const client = new Gitpod({ + baseURL: 'http://localhost:5000/', + bearerToken: 'My Bearer Token', + fetch: testFetch, + }); + + await client.patch('/foo'); + expect(capturedRequest?.method).toEqual('PATCH'); + }); + + describe('baseUrl', () => { + test('trailing slash', () => { + const client = new Gitpod({ + baseURL: 'http://localhost:5000/custom/path/', + bearerToken: 'My Bearer Token', + }); + expect(client.buildURL('/foo', null)).toEqual('http://localhost:5000/custom/path/foo'); + }); + + test('no trailing slash', () => { + const client = new Gitpod({ + baseURL: 'http://localhost:5000/custom/path', + bearerToken: 'My Bearer Token', + }); + expect(client.buildURL('/foo', null)).toEqual('http://localhost:5000/custom/path/foo'); + }); + + afterEach(() => { + process.env['GITPOD_BASE_URL'] = undefined; + }); + + test('explicit option', () => { + const client = new Gitpod({ baseURL: 'https://example.com', bearerToken: 'My Bearer Token' }); + expect(client.baseURL).toEqual('https://example.com'); + }); + + test('env variable', () => { + process.env['GITPOD_BASE_URL'] = 'https://example.com/from_env'; + const client = new Gitpod({ bearerToken: 'My Bearer Token' }); + expect(client.baseURL).toEqual('https://example.com/from_env'); + }); + + test('empty env variable', () => { + process.env['GITPOD_BASE_URL'] = ''; // empty + const client = new Gitpod({ bearerToken: 'My Bearer Token' }); + expect(client.baseURL).toEqual('https://app.gitpod.io/api'); + }); + + test('blank env variable', () => { + process.env['GITPOD_BASE_URL'] = ' '; // blank + const client = new Gitpod({ bearerToken: 'My Bearer Token' }); + expect(client.baseURL).toEqual('https://app.gitpod.io/api'); + }); + }); + + test('maxRetries option is correctly set', () => { + const client = new Gitpod({ maxRetries: 4, bearerToken: 'My Bearer Token' }); + expect(client.maxRetries).toEqual(4); + + // default + const client2 = new Gitpod({ bearerToken: 'My Bearer Token' }); + expect(client2.maxRetries).toEqual(2); + }); + + test('with environment variable arguments', () => { + // set options via env var + process.env['GITPOD_API_KEY'] = 'My Bearer Token'; + const client = new Gitpod(); + expect(client.bearerToken).toBe('My Bearer Token'); + }); + + test('with overridden environment variable arguments', () => { + // set options via env var + process.env['GITPOD_API_KEY'] = 'another My Bearer Token'; + const client = new Gitpod({ bearerToken: 'My Bearer Token' }); + expect(client.bearerToken).toBe('My Bearer Token'); + }); +}); + +describe('request building', () => { + const client = new Gitpod({ bearerToken: 'My Bearer Token' }); + + describe('custom headers', () => { + test('handles undefined', () => { + const { req } = client.buildRequest({ + path: '/foo', + method: 'post', + body: { value: 'hello' }, + headers: { 'X-Foo': 'baz', 'x-foo': 'bar', 'x-Foo': undefined, 'x-baz': 'bam', 'X-Baz': null }, + }); + expect(req.headers.get('x-foo')).toEqual('bar'); + expect(req.headers.get('x-Foo')).toEqual('bar'); + expect(req.headers.get('X-Foo')).toEqual('bar'); + expect(req.headers.get('x-baz')).toEqual(null); + }); + }); +}); + +describe('default encoder', () => { + const client = new Gitpod({ bearerToken: 'My Bearer Token' }); + + class Serializable { + toJSON() { + return { $type: 'Serializable' }; + } + } + class Collection<T> { + #things: T[]; + constructor(things: T[]) { + this.#things = Array.from(things); + } + toJSON() { + return Array.from(this.#things); + } + [Symbol.iterator]() { + return this.#things[Symbol.iterator]; + } + } + for (const jsonValue of [{}, [], { __proto__: null }, new Serializable(), new Collection(['item'])]) { + test(`serializes ${util.inspect(jsonValue)} as json`, () => { + const { req } = client.buildRequest({ + path: '/foo', + method: 'post', + body: jsonValue, + }); + expect(req.headers).toBeInstanceOf(Headers); + expect(req.headers.get('content-type')).toEqual('application/json'); + expect(req.body).toBe(JSON.stringify(jsonValue)); + }); + } + + const encoder = new TextEncoder(); + const asyncIterable = (async function* () { + yield encoder.encode('a\n'); + yield encoder.encode('b\n'); + yield encoder.encode('c\n'); + })(); + for (const streamValue of [ + [encoder.encode('a\nb\nc\n')][Symbol.iterator](), + new Response('a\nb\nc\n').body, + asyncIterable, + ]) { + test(`converts ${util.inspect(streamValue)} to ReadableStream`, async () => { + const { req } = client.buildRequest({ + path: '/foo', + method: 'post', + body: streamValue, + }); + expect(req.headers).toBeInstanceOf(Headers); + expect(req.headers.get('content-type')).toEqual(null); + expect(req.body).toBeInstanceOf(ReadableStream); + expect(await new Response(req.body).text()).toBe('a\nb\nc\n'); + }); + } + + test(`can set content-type for ReadableStream`, async () => { + const { req } = client.buildRequest({ + path: '/foo', + method: 'post', + body: new Response('a\nb\nc\n').body, + headers: { 'Content-Type': 'text/plain' }, + }); + expect(req.headers).toBeInstanceOf(Headers); + expect(req.headers.get('content-type')).toEqual('text/plain'); + expect(req.body).toBeInstanceOf(ReadableStream); + expect(await new Response(req.body).text()).toBe('a\nb\nc\n'); + }); +}); + +describe('retries', () => { + test('retry on timeout', async () => { + let count = 0; + const testFetch = async ( + url: string | URL | Request, + { signal }: RequestInit = {}, + ): Promise<Response> => { + if (count++ === 0) { + return new Promise( + (resolve, reject) => signal?.addEventListener('abort', () => reject(new Error('timed out'))), + ); + } + return new Response(JSON.stringify({ a: 1 }), { headers: { 'Content-Type': 'application/json' } }); + }; + + const client = new Gitpod({ bearerToken: 'My Bearer Token', timeout: 10, fetch: testFetch }); + + expect(await client.request({ path: '/foo', method: 'get' })).toEqual({ a: 1 }); + expect(count).toEqual(2); + expect( + await client + .request({ path: '/foo', method: 'get' }) + .asResponse() + .then((r) => r.text()), + ).toEqual(JSON.stringify({ a: 1 })); + expect(count).toEqual(3); + }); + + test('retry count header', async () => { + let count = 0; + let capturedRequest: RequestInit | undefined; + const testFetch = async (url: string | URL | Request, init: RequestInit = {}): Promise<Response> => { + count++; + if (count <= 2) { + return new Response(undefined, { + status: 429, + headers: { + 'Retry-After': '0.1', + }, + }); + } + capturedRequest = init; + return new Response(JSON.stringify({ a: 1 }), { headers: { 'Content-Type': 'application/json' } }); + }; + + const client = new Gitpod({ bearerToken: 'My Bearer Token', fetch: testFetch, maxRetries: 4 }); + + expect(await client.request({ path: '/foo', method: 'get' })).toEqual({ a: 1 }); + + expect((capturedRequest!.headers as Headers).get('x-stainless-retry-count')).toEqual('2'); + expect(count).toEqual(3); + }); + + test('omit retry count header', async () => { + let count = 0; + let capturedRequest: RequestInit | undefined; + const testFetch = async (url: string | URL | Request, init: RequestInit = {}): Promise<Response> => { + count++; + if (count <= 2) { + return new Response(undefined, { + status: 429, + headers: { + 'Retry-After': '0.1', + }, + }); + } + capturedRequest = init; + return new Response(JSON.stringify({ a: 1 }), { headers: { 'Content-Type': 'application/json' } }); + }; + const client = new Gitpod({ bearerToken: 'My Bearer Token', fetch: testFetch, maxRetries: 4 }); + + expect( + await client.request({ + path: '/foo', + method: 'get', + headers: { 'X-Stainless-Retry-Count': null }, + }), + ).toEqual({ a: 1 }); + + expect((capturedRequest!.headers as Headers).has('x-stainless-retry-count')).toBe(false); + }); + + test('omit retry count header by default', async () => { + let count = 0; + let capturedRequest: RequestInit | undefined; + const testFetch = async (url: string | URL | Request, init: RequestInit = {}): Promise<Response> => { + count++; + if (count <= 2) { + return new Response(undefined, { + status: 429, + headers: { + 'Retry-After': '0.1', + }, + }); + } + capturedRequest = init; + return new Response(JSON.stringify({ a: 1 }), { headers: { 'Content-Type': 'application/json' } }); + }; + const client = new Gitpod({ + bearerToken: 'My Bearer Token', + fetch: testFetch, + maxRetries: 4, + defaultHeaders: { 'X-Stainless-Retry-Count': null }, + }); + + expect( + await client.request({ + path: '/foo', + method: 'get', + }), + ).toEqual({ a: 1 }); + + expect(capturedRequest!.headers as Headers).not.toHaveProperty('x-stainless-retry-count'); + }); + + test('overwrite retry count header', async () => { + let count = 0; + let capturedRequest: RequestInit | undefined; + const testFetch = async (url: string | URL | Request, init: RequestInit = {}): Promise<Response> => { + count++; + if (count <= 2) { + return new Response(undefined, { + status: 429, + headers: { + 'Retry-After': '0.1', + }, + }); + } + capturedRequest = init; + return new Response(JSON.stringify({ a: 1 }), { headers: { 'Content-Type': 'application/json' } }); + }; + const client = new Gitpod({ bearerToken: 'My Bearer Token', fetch: testFetch, maxRetries: 4 }); + + expect( + await client.request({ + path: '/foo', + method: 'get', + headers: { 'X-Stainless-Retry-Count': '42' }, + }), + ).toEqual({ a: 1 }); + + expect((capturedRequest!.headers as Headers).get('x-stainless-retry-count')).toEqual('42'); + }); + + test('retry on 429 with retry-after', async () => { + let count = 0; + const testFetch = async ( + url: string | URL | Request, + { signal }: RequestInit = {}, + ): Promise<Response> => { + if (count++ === 0) { + return new Response(undefined, { + status: 429, + headers: { + 'Retry-After': '0.1', + }, + }); + } + return new Response(JSON.stringify({ a: 1 }), { headers: { 'Content-Type': 'application/json' } }); + }; + + const client = new Gitpod({ bearerToken: 'My Bearer Token', fetch: testFetch }); + + expect(await client.request({ path: '/foo', method: 'get' })).toEqual({ a: 1 }); + expect(count).toEqual(2); + expect( + await client + .request({ path: '/foo', method: 'get' }) + .asResponse() + .then((r) => r.text()), + ).toEqual(JSON.stringify({ a: 1 })); + expect(count).toEqual(3); + }); + + test('retry on 429 with retry-after-ms', async () => { + let count = 0; + const testFetch = async ( + url: string | URL | Request, + { signal }: RequestInit = {}, + ): Promise<Response> => { + if (count++ === 0) { + return new Response(undefined, { + status: 429, + headers: { + 'Retry-After-Ms': '10', + }, + }); + } + return new Response(JSON.stringify({ a: 1 }), { headers: { 'Content-Type': 'application/json' } }); + }; + + const client = new Gitpod({ bearerToken: 'My Bearer Token', fetch: testFetch }); + + expect(await client.request({ path: '/foo', method: 'get' })).toEqual({ a: 1 }); + expect(count).toEqual(2); + expect( + await client + .request({ path: '/foo', method: 'get' }) + .asResponse() + .then((r) => r.text()), + ).toEqual(JSON.stringify({ a: 1 })); + expect(count).toEqual(3); + }); +}); diff --git a/tests/internal/decoders/line.test.ts b/tests/internal/decoders/line.test.ts new file mode 100644 index 0000000..9f45693 --- /dev/null +++ b/tests/internal/decoders/line.test.ts @@ -0,0 +1,128 @@ +import { findDoubleNewlineIndex, LineDecoder } from '@gitpod/sdk/internal/decoders/line'; + +function decodeChunks(chunks: string[], { flush }: { flush: boolean } = { flush: false }): string[] { + const decoder = new LineDecoder(); + const lines: string[] = []; + for (const chunk of chunks) { + lines.push(...decoder.decode(chunk)); + } + + if (flush) { + lines.push(...decoder.flush()); + } + + return lines; +} + +describe('line decoder', () => { + test('basic', () => { + // baz is not included because the line hasn't ended yet + expect(decodeChunks(['foo', ' bar\nbaz'])).toEqual(['foo bar']); + }); + + test('basic with \\r', () => { + expect(decodeChunks(['foo', ' bar\r\nbaz'])).toEqual(['foo bar']); + expect(decodeChunks(['foo', ' bar\r\nbaz'], { flush: true })).toEqual(['foo bar', 'baz']); + }); + + test('trailing new lines', () => { + expect(decodeChunks(['foo', ' bar', 'baz\n', 'thing\n'])).toEqual(['foo barbaz', 'thing']); + }); + + test('trailing new lines with \\r', () => { + expect(decodeChunks(['foo', ' bar', 'baz\r\n', 'thing\r\n'])).toEqual(['foo barbaz', 'thing']); + }); + + test('escaped new lines', () => { + expect(decodeChunks(['foo', ' bar\\nbaz\n'])).toEqual(['foo bar\\nbaz']); + }); + + test('escaped new lines with \\r', () => { + expect(decodeChunks(['foo', ' bar\\r\\nbaz\n'])).toEqual(['foo bar\\r\\nbaz']); + }); + + test('\\r & \\n split across multiple chunks', () => { + expect(decodeChunks(['foo\r', '\n', 'bar'], { flush: true })).toEqual(['foo', 'bar']); + }); + + test('single \\r', () => { + expect(decodeChunks(['foo\r', 'bar'], { flush: true })).toEqual(['foo', 'bar']); + }); + + test('double \\r', () => { + expect(decodeChunks(['foo\r', 'bar\r'], { flush: true })).toEqual(['foo', 'bar']); + expect(decodeChunks(['foo\r', '\r', 'bar'], { flush: true })).toEqual(['foo', '', 'bar']); + // implementation detail that we don't yield the single \r line until a new \r or \n is encountered + expect(decodeChunks(['foo\r', '\r', 'bar'], { flush: false })).toEqual(['foo']); + }); + + test('double \\r then \\r\\n', () => { + expect(decodeChunks(['foo\r', '\r', '\r', '\n', 'bar', '\n'])).toEqual(['foo', '', '', 'bar']); + expect(decodeChunks(['foo\n', '\n', '\n', 'bar', '\n'])).toEqual(['foo', '', '', 'bar']); + }); + + test('double newline', () => { + expect(decodeChunks(['foo\n\nbar'], { flush: true })).toEqual(['foo', '', 'bar']); + expect(decodeChunks(['foo', '\n', '\nbar'], { flush: true })).toEqual(['foo', '', 'bar']); + expect(decodeChunks(['foo\n', '\n', 'bar'], { flush: true })).toEqual(['foo', '', 'bar']); + expect(decodeChunks(['foo', '\n', '\n', 'bar'], { flush: true })).toEqual(['foo', '', 'bar']); + }); + + test('multi-byte characters across chunks', () => { + const decoder = new LineDecoder(); + + // bytes taken from the string 'известни' and arbitrarily split + // so that some multi-byte characters span multiple chunks + expect(decoder.decode(new Uint8Array([0xd0]))).toHaveLength(0); + expect(decoder.decode(new Uint8Array([0xb8, 0xd0, 0xb7, 0xd0]))).toHaveLength(0); + expect( + decoder.decode(new Uint8Array([0xb2, 0xd0, 0xb5, 0xd1, 0x81, 0xd1, 0x82, 0xd0, 0xbd, 0xd0, 0xb8])), + ).toHaveLength(0); + + const decoded = decoder.decode(new Uint8Array([0xa])); + expect(decoded).toEqual(['известни']); + }); + + test('flushing trailing newlines', () => { + expect(decodeChunks(['foo\n', '\nbar'], { flush: true })).toEqual(['foo', '', 'bar']); + }); + + test('flushing empty buffer', () => { + expect(decodeChunks([], { flush: true })).toEqual([]); + }); +}); + +describe('findDoubleNewlineIndex', () => { + test('finds \\n\\n', () => { + expect(findDoubleNewlineIndex(new TextEncoder().encode('foo\n\nbar'))).toBe(5); + expect(findDoubleNewlineIndex(new TextEncoder().encode('\n\nbar'))).toBe(2); + expect(findDoubleNewlineIndex(new TextEncoder().encode('foo\n\n'))).toBe(5); + expect(findDoubleNewlineIndex(new TextEncoder().encode('\n\n'))).toBe(2); + }); + + test('finds \\r\\r', () => { + expect(findDoubleNewlineIndex(new TextEncoder().encode('foo\r\rbar'))).toBe(5); + expect(findDoubleNewlineIndex(new TextEncoder().encode('\r\rbar'))).toBe(2); + expect(findDoubleNewlineIndex(new TextEncoder().encode('foo\r\r'))).toBe(5); + expect(findDoubleNewlineIndex(new TextEncoder().encode('\r\r'))).toBe(2); + }); + + test('finds \\r\\n\\r\\n', () => { + expect(findDoubleNewlineIndex(new TextEncoder().encode('foo\r\n\r\nbar'))).toBe(7); + expect(findDoubleNewlineIndex(new TextEncoder().encode('\r\n\r\nbar'))).toBe(4); + expect(findDoubleNewlineIndex(new TextEncoder().encode('foo\r\n\r\n'))).toBe(7); + expect(findDoubleNewlineIndex(new TextEncoder().encode('\r\n\r\n'))).toBe(4); + }); + + test('returns -1 when no double newline found', () => { + expect(findDoubleNewlineIndex(new TextEncoder().encode('foo\nbar'))).toBe(-1); + expect(findDoubleNewlineIndex(new TextEncoder().encode('foo\rbar'))).toBe(-1); + expect(findDoubleNewlineIndex(new TextEncoder().encode('foo\r\nbar'))).toBe(-1); + expect(findDoubleNewlineIndex(new TextEncoder().encode(''))).toBe(-1); + }); + + test('handles incomplete patterns', () => { + expect(findDoubleNewlineIndex(new TextEncoder().encode('foo\r\n\r'))).toBe(-1); + expect(findDoubleNewlineIndex(new TextEncoder().encode('foo\r\n'))).toBe(-1); + }); +}); diff --git a/tests/path.test.ts b/tests/path.test.ts new file mode 100644 index 0000000..3c95a0b --- /dev/null +++ b/tests/path.test.ts @@ -0,0 +1,318 @@ +import { createPathTagFunction, encodeURIPath } from '@gitpod/sdk/internal/utils/path'; +import { inspect } from 'node:util'; + +describe('path template tag function', () => { + test('validates input', () => { + const testParams = ['', '.', '..', 'x', '%2e', '%2E', '%2e%2e', '%2E%2e', '%2e%2E', '%2E%2E']; + const testCases = [ + ['/path_params/', '/a'], + ['/path_params/', '/'], + ['/path_params/', ''], + ['', '/a'], + ['', '/'], + ['', ''], + ['a'], + [''], + ['/path_params/', ':initiate'], + ['/path_params/', '.json'], + ['/path_params/', '?beta=true'], + ['/path_params/', '.?beta=true'], + ['/path_params/', '/', '/download'], + ['/path_params/', '-', '/download'], + ['/path_params/', '', '/download'], + ['/path_params/', '.', '/download'], + ['/path_params/', '..', '/download'], + ['/plain/path'], + ]; + + function paramPermutations(len: number): string[][] { + if (len === 0) return []; + if (len === 1) return testParams.map((e) => [e]); + const rest = paramPermutations(len - 1); + return testParams.flatMap((e) => rest.map((r) => [e, ...r])); + } + + // we need to test how %2E is handled so we use a custom encoder that does no escaping + const rawPath = createPathTagFunction((s) => s); + + const results: { + [pathParts: string]: { + [params: string]: { valid: boolean; result?: string; error?: string }; + }; + } = {}; + + for (const pathParts of testCases) { + const pathResults: Record<string, { valid: boolean; result?: string; error?: string }> = {}; + results[JSON.stringify(pathParts)] = pathResults; + for (const params of paramPermutations(pathParts.length - 1)) { + const stringRaw = String.raw({ raw: pathParts }, ...params); + const plainString = String.raw( + { raw: pathParts.map((e) => e.replace(/\./g, 'x')) }, + ...params.map((e) => 'X'.repeat(e.length)), + ); + const normalizedStringRaw = new URL(stringRaw, 'https://example.com').href; + const normalizedPlainString = new URL(plainString, 'https://example.com').href; + const pathResultsKey = JSON.stringify(params); + try { + const result = rawPath(pathParts, ...params); + expect(result).toBe(stringRaw); + // there are no special segments, so the length of the normalized path is + // equal to the length of the normalized plain path. + expect(normalizedStringRaw.length).toBe(normalizedPlainString.length); + pathResults[pathResultsKey] = { + valid: true, + result, + }; + } catch (e) { + const error = String(e); + expect(error).toMatch(/Path parameters result in path with invalid segment/); + // there are special segments, so the length of the normalized path is + // different than the length of the normalized plain path. + expect(normalizedStringRaw.length).not.toBe(normalizedPlainString.length); + pathResults[pathResultsKey] = { + valid: false, + error, + }; + } + } + } + + expect(results).toMatchObject({ + '["/path_params/","/a"]': { + '["x"]': { valid: true, result: '/path_params/x/a' }, + '[""]': { valid: true, result: '/path_params//a' }, + '["%2E%2e"]': { + valid: false, + error: + 'Error: Path parameters result in path with invalid segments:\n' + + '/path_params/%2E%2e/a\n' + + ' ^^^^^^', + }, + '["%2E"]': { + valid: false, + error: + 'Error: Path parameters result in path with invalid segments:\n' + + '/path_params/%2E/a\n' + + ' ^^^', + }, + }, + '["/path_params/","/"]': { + '["x"]': { valid: true, result: '/path_params/x/' }, + '[""]': { valid: true, result: '/path_params//' }, + '["%2e%2E"]': { + valid: false, + error: + 'Error: Path parameters result in path with invalid segments:\n' + + '/path_params/%2e%2E/\n' + + ' ^^^^^^', + }, + '["%2e"]': { + valid: false, + error: + 'Error: Path parameters result in path with invalid segments:\n' + + '/path_params/%2e/\n' + + ' ^^^', + }, + }, + '["/path_params/",""]': { + '[""]': { valid: true, result: '/path_params/' }, + '["x"]': { valid: true, result: '/path_params/x' }, + '["%2E"]': { + valid: false, + error: + 'Error: Path parameters result in path with invalid segments:\n' + + '/path_params/%2E\n' + + ' ^^^', + }, + '["%2E%2e"]': { + valid: false, + error: + 'Error: Path parameters result in path with invalid segments:\n' + + '/path_params/%2E%2e\n' + + ' ^^^^^^', + }, + }, + '["","/a"]': { + '[""]': { valid: true, result: '/a' }, + '["x"]': { valid: true, result: 'x/a' }, + '["%2E"]': { + valid: false, + error: 'Error: Path parameters result in path with invalid segments:\n%2E/a\n^^^', + }, + '["%2e%2E"]': { + valid: false, + error: 'Error: Path parameters result in path with invalid segments:\n' + '%2e%2E/a\n' + '^^^^^^', + }, + }, + '["","/"]': { + '["x"]': { valid: true, result: 'x/' }, + '[""]': { valid: true, result: '/' }, + '["%2E%2e"]': { + valid: false, + error: 'Error: Path parameters result in path with invalid segments:\n' + '%2E%2e/\n' + '^^^^^^', + }, + '["."]': { + valid: false, + error: 'Error: Path parameters result in path with invalid segments:\n./\n^', + }, + }, + '["",""]': { + '[""]': { valid: true, result: '' }, + '["x"]': { valid: true, result: 'x' }, + '[".."]': { + valid: false, + error: 'Error: Path parameters result in path with invalid segments:\n..\n^^', + }, + '["."]': { + valid: false, + error: 'Error: Path parameters result in path with invalid segments:\n.\n^', + }, + }, + '["a"]': {}, + '[""]': {}, + '["/path_params/",":initiate"]': { + '[""]': { valid: true, result: '/path_params/:initiate' }, + '["."]': { valid: true, result: '/path_params/.:initiate' }, + }, + '["/path_params/",".json"]': { + '["x"]': { valid: true, result: '/path_params/x.json' }, + '["."]': { valid: true, result: '/path_params/..json' }, + }, + '["/path_params/","?beta=true"]': { + '["x"]': { valid: true, result: '/path_params/x?beta=true' }, + '[""]': { valid: true, result: '/path_params/?beta=true' }, + '["%2E%2E"]': { + valid: false, + error: + 'Error: Path parameters result in path with invalid segments:\n' + + '/path_params/%2E%2E?beta=true\n' + + ' ^^^^^^', + }, + '["%2e%2E"]': { + valid: false, + error: + 'Error: Path parameters result in path with invalid segments:\n' + + '/path_params/%2e%2E?beta=true\n' + + ' ^^^^^^', + }, + }, + '["/path_params/",".?beta=true"]': { + '[".."]': { valid: true, result: '/path_params/...?beta=true' }, + '["x"]': { valid: true, result: '/path_params/x.?beta=true' }, + '[""]': { + valid: false, + error: + 'Error: Path parameters result in path with invalid segments:\n' + + '/path_params/.?beta=true\n' + + ' ^', + }, + '["%2e"]': { + valid: false, + error: + 'Error: Path parameters result in path with invalid segments:\n' + + '/path_params/%2e.?beta=true\n' + + ' ^^^^', + }, + }, + '["/path_params/","/","/download"]': { + '["",""]': { valid: true, result: '/path_params///download' }, + '["","x"]': { valid: true, result: '/path_params//x/download' }, + '[".","%2e"]': { + valid: false, + error: + 'Error: Path parameters result in path with invalid segments:\n' + + '/path_params/./%2e/download\n' + + ' ^ ^^^', + }, + '["%2E%2e","%2e"]': { + valid: false, + error: + 'Error: Path parameters result in path with invalid segments:\n' + + '/path_params/%2E%2e/%2e/download\n' + + ' ^^^^^^ ^^^', + }, + }, + '["/path_params/","-","/download"]': { + '["","%2e"]': { valid: true, result: '/path_params/-%2e/download' }, + '["%2E",".."]': { valid: true, result: '/path_params/%2E-../download' }, + }, + '["/path_params/","","/download"]': { + '["%2E%2e","%2e%2E"]': { valid: true, result: '/path_params/%2E%2e%2e%2E/download' }, + '["%2E",".."]': { valid: true, result: '/path_params/%2E../download' }, + '["","%2E"]': { + valid: false, + error: + 'Error: Path parameters result in path with invalid segments:\n' + + '/path_params/%2E/download\n' + + ' ^^^', + }, + '["%2E","."]': { + valid: false, + error: + 'Error: Path parameters result in path with invalid segments:\n' + + '/path_params/%2E./download\n' + + ' ^^^^', + }, + }, + '["/path_params/",".","/download"]': { + '["%2e%2e",""]': { valid: true, result: '/path_params/%2e%2e./download' }, + '["","%2e%2e"]': { valid: true, result: '/path_params/.%2e%2e/download' }, + '["",""]': { + valid: false, + error: + 'Error: Path parameters result in path with invalid segments:\n' + + '/path_params/./download\n' + + ' ^', + }, + '["","."]': { + valid: false, + error: + 'Error: Path parameters result in path with invalid segments:\n' + + '/path_params/../download\n' + + ' ^^', + }, + }, + '["/path_params/","..","/download"]': { + '["","%2E"]': { valid: true, result: '/path_params/..%2E/download' }, + '["","x"]': { valid: true, result: '/path_params/..x/download' }, + '["",""]': { + valid: false, + error: + 'Error: Path parameters result in path with invalid segments:\n' + + '/path_params/../download\n' + + ' ^^', + }, + }, + }); + }); +}); + +describe('encodeURIPath', () => { + const testCases: string[] = [ + '', + // Every ASCII character + ...Array.from({ length: 0x7f }, (_, i) => String.fromCharCode(i)), + // Unicode BMP codepoint + 'å', + // Unicode supplementary codepoint + '😃', + ]; + + for (const param of testCases) { + test('properly encodes ' + inspect(param), () => { + const encoded = encodeURIPath(param); + const naiveEncoded = encodeURIComponent(param); + // we should never encode more characters than encodeURIComponent + expect(naiveEncoded.length).toBeGreaterThanOrEqual(encoded.length); + expect(decodeURIComponent(encoded)).toBe(param); + }); + } + + test("leaves ':' intact", () => { + expect(encodeURIPath(':')).toBe(':'); + }); + + test("leaves '@' intact", () => { + expect(encodeURIPath('@')).toBe('@'); + }); +}); diff --git a/tests/stringifyQuery.test.ts b/tests/stringifyQuery.test.ts new file mode 100644 index 0000000..a5c8902 --- /dev/null +++ b/tests/stringifyQuery.test.ts @@ -0,0 +1,29 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { Gitpod } from '@gitpod/sdk'; + +const { stringifyQuery } = Gitpod.prototype as any; + +describe(stringifyQuery, () => { + for (const [input, expected] of [ + [{ a: '1', b: 2, c: true }, 'a=1&b=2&c=true'], + [{ a: null, b: false, c: undefined }, 'a=&b=false'], + [{ 'a/b': 1.28341 }, `${encodeURIComponent('a/b')}=1.28341`], + [ + { 'a/b': 'c/d', 'e=f': 'g&h' }, + `${encodeURIComponent('a/b')}=${encodeURIComponent('c/d')}&${encodeURIComponent( + 'e=f', + )}=${encodeURIComponent('g&h')}`, + ], + ]) { + it(`${JSON.stringify(input)} -> ${expected}`, () => { + expect(stringifyQuery(input)).toEqual(expected); + }); + } + + for (const value of [[], {}, new Date()]) { + it(`${JSON.stringify(value)} -> <error>`, () => { + expect(() => stringifyQuery({ value })).toThrow(`Cannot stringify type ${typeof value}`); + }); + } +}); diff --git a/tests/uploads.test.ts b/tests/uploads.test.ts new file mode 100644 index 0000000..27bf8b3 --- /dev/null +++ b/tests/uploads.test.ts @@ -0,0 +1,107 @@ +import fs from 'fs'; +import type { ResponseLike } from '@gitpod/sdk/internal/to-file'; +import { toFile } from '@gitpod/sdk/core/uploads'; +import { File } from 'node:buffer'; + +class MyClass { + name: string = 'foo'; +} + +function mockResponse({ url, content }: { url: string; content?: Blob }): ResponseLike { + return { + url, + blob: async () => content || new Blob([]), + }; +} + +describe('toFile', () => { + it('throws a helpful error for mismatched types', async () => { + await expect( + // @ts-expect-error intentionally mismatched type + toFile({ foo: 'string' }), + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"Unexpected data type: object; constructor: Object; props: ["foo"]"`, + ); + + await expect( + // @ts-expect-error intentionally mismatched type + toFile(new MyClass()), + ).rejects.toThrowErrorMatchingInlineSnapshot( + `"Unexpected data type: object; constructor: MyClass; props: ["name"]"`, + ); + }); + + it('disallows string at the type-level', async () => { + // @ts-expect-error we intentionally do not type support for `string` + // to help people avoid passing a file path + const file = await toFile('contents'); + expect(file.text()).resolves.toEqual('contents'); + }); + + it('extracts a file name from a Response', async () => { + const response = mockResponse({ url: 'https://example.com/my/audio.mp3' }); + const file = await toFile(response); + expect(file.name).toEqual('audio.mp3'); + }); + + it('extracts a file name from a File', async () => { + const input = new File(['foo'], 'input.jsonl'); + const file = await toFile(input); + expect(file.name).toEqual('input.jsonl'); + }); + + it('extracts a file name from a ReadStream', async () => { + const input = fs.createReadStream('tests/uploads.test.ts'); + const file = await toFile(input); + expect(file.name).toEqual('uploads.test.ts'); + }); + + it('does not copy File objects', async () => { + const input = new File(['foo'], 'input.jsonl', { type: 'jsonl' }); + const file = await toFile(input); + expect(file).toBe(input); + expect(file.name).toEqual('input.jsonl'); + expect(file.type).toBe('jsonl'); + }); + + it('is assignable to File and Blob', async () => { + const input = new File(['foo'], 'input.jsonl', { type: 'jsonl' }); + const result = await toFile(input); + const file: File = result; + const blob: Blob = result; + void file, blob; + }); +}); + +describe('missing File error message', () => { + let prevGlobalFile: unknown; + let prevNodeFile: unknown; + beforeEach(() => { + // The file shim captures the global File object when it's first imported. + // Reset modules before each test so we can test the error thrown when it's undefined. + jest.resetModules(); + const buffer = require('node:buffer'); + // @ts-ignore + prevGlobalFile = globalThis.File; + prevNodeFile = buffer.File; + // @ts-ignore + globalThis.File = undefined; + buffer.File = undefined; + }); + afterEach(() => { + // Clean up + // @ts-ignore + globalThis.File = prevGlobalFile; + require('node:buffer').File = prevNodeFile; + jest.resetModules(); + }); + + test('is thrown', async () => { + const uploads = await import('@gitpod/sdk/core/uploads'); + await expect( + uploads.toFile(mockResponse({ url: 'https://example.com/my/audio.mp3' })), + ).rejects.toMatchInlineSnapshot( + `[Error: \`File\` is not defined as a global, which is required for file uploads.]`, + ); + }); +}); diff --git a/tsc-multi.json b/tsc-multi.json new file mode 100644 index 0000000..170bac7 --- /dev/null +++ b/tsc-multi.json @@ -0,0 +1,7 @@ +{ + "targets": [ + { "extname": ".js", "module": "commonjs", "shareHelpers": "internal/tslib.js" }, + { "extname": ".mjs", "module": "esnext", "shareHelpers": "internal/tslib.mjs" } + ], + "projects": ["tsconfig.build.json"] +} diff --git a/tsconfig.build.json b/tsconfig.build.json new file mode 100644 index 0000000..0460cd2 --- /dev/null +++ b/tsconfig.build.json @@ -0,0 +1,18 @@ +{ + "extends": "./tsconfig.json", + "include": ["dist/src"], + "exclude": [], + "compilerOptions": { + "rootDir": "./dist/src", + "paths": { + "@gitpod/sdk/*": ["dist/src/*"], + "@gitpod/sdk": ["dist/src/index.ts"] + }, + "noEmit": false, + "declaration": true, + "declarationMap": true, + "outDir": "dist", + "pretty": true, + "sourceMap": true + } +} diff --git a/tsconfig.deno.json b/tsconfig.deno.json new file mode 100644 index 0000000..849e070 --- /dev/null +++ b/tsconfig.deno.json @@ -0,0 +1,15 @@ +{ + "extends": "./tsconfig.json", + "include": ["dist-deno"], + "exclude": [], + "compilerOptions": { + "rootDir": "./dist-deno", + "lib": ["es2020", "DOM"], + "noEmit": true, + "declaration": true, + "declarationMap": true, + "outDir": "dist-deno", + "pretty": true, + "sourceMap": true + } +} diff --git a/tsconfig.dist-src.json b/tsconfig.dist-src.json new file mode 100644 index 0000000..c550e29 --- /dev/null +++ b/tsconfig.dist-src.json @@ -0,0 +1,11 @@ +{ + // this config is included in the published src directory to prevent TS errors + // from appearing when users go to source, and VSCode opens the source .ts file + // via declaration maps + "include": ["index.ts"], + "compilerOptions": { + "target": "ES2015", + "lib": ["DOM", "DOM.Iterable", "ES2018"], + "moduleResolution": "node" + } +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..db8ba0b --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,38 @@ +{ + "include": ["src", "tests", "examples"], + "exclude": [], + "compilerOptions": { + "target": "es2020", + "lib": ["es2020"], + "module": "commonjs", + "moduleResolution": "node", + "esModuleInterop": true, + "baseUrl": "./", + "paths": { + "@gitpod/sdk/*": ["src/*"], + "@gitpod/sdk": ["src/index.ts"] + }, + "noEmit": true, + + "resolveJsonModule": true, + + "forceConsistentCasingInFileNames": true, + + "strict": true, + "noImplicitAny": true, + "strictNullChecks": true, + "strictFunctionTypes": true, + "strictBindCallApply": true, + "strictPropertyInitialization": true, + "noImplicitThis": true, + "noImplicitReturns": true, + "alwaysStrict": true, + "exactOptionalPropertyTypes": true, + "noUncheckedIndexedAccess": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "isolatedModules": false, + + "skipLibCheck": true + } +} diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 0000000..43da555 --- /dev/null +++ b/yarn.lock @@ -0,0 +1,3506 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@aashutoshrathi/word-wrap@^1.2.3": + version "1.2.6" + resolved "https://registry.yarnpkg.com/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz#bd9154aec9983f77b3a034ecaa015c2e4201f6cf" + integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA== + +"@ampproject/remapping@^2.2.0": + version "2.2.1" + resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.1.tgz#99e8e11851128b8702cd57c33684f1d0f260b630" + integrity sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg== + dependencies: + "@jridgewell/gen-mapping" "^0.3.0" + "@jridgewell/trace-mapping" "^0.3.9" + +"@andrewbranch/untar.js@^1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@andrewbranch/untar.js/-/untar.js-1.0.3.tgz#ba9494f85eb83017c5c855763969caf1d0adea00" + integrity sha512-Jh15/qVmrLGhkKJBdXlK1+9tY4lZruYjsgkDFj08ZmDiWVBLJcqkok7Z0/R0In+i1rScBpJlSvrTS2Lm41Pbnw== + +"@arethetypeswrong/cli@^0.17.0": + version "0.17.0" + resolved "https://registry.yarnpkg.com/@arethetypeswrong/cli/-/cli-0.17.0.tgz#f97f10926b3f9f9eb5117550242d2e06c25cadac" + integrity sha512-xSMW7bfzVWpYw5JFgZqBXqr6PdR0/REmn3DkxCES5N0JTcB0CVgbIynJCvKBFmXaPc3hzmmTrb7+yPDRoOSZdA== + dependencies: + "@arethetypeswrong/core" "0.17.0" + chalk "^4.1.2" + cli-table3 "^0.6.3" + commander "^10.0.1" + marked "^9.1.2" + marked-terminal "^7.1.0" + semver "^7.5.4" + +"@arethetypeswrong/core@0.17.0": + version "0.17.0" + resolved "https://registry.yarnpkg.com/@arethetypeswrong/core/-/core-0.17.0.tgz#abb3b5f425056d37193644c2a2de4aecf866b76b" + integrity sha512-FHyhFizXNetigTVsIhqXKGYLpazPS5YNojEPpZEUcBPt9wVvoEbNIvG+hybuBR+pjlRcbyuqhukHZm1fr+bDgA== + dependencies: + "@andrewbranch/untar.js" "^1.0.3" + cjs-module-lexer "^1.2.3" + fflate "^0.8.2" + lru-cache "^10.4.3" + semver "^7.5.4" + typescript "5.6.1-rc" + validate-npm-package-name "^5.0.0" + +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.22.13", "@babel/code-frame@^7.23.5": + version "7.23.5" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.23.5.tgz#9009b69a8c602293476ad598ff53e4562e15c244" + integrity sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA== + dependencies: + "@babel/highlight" "^7.23.4" + chalk "^2.4.2" + +"@babel/compat-data@^7.23.5": + version "7.23.5" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.23.5.tgz#ffb878728bb6bdcb6f4510aa51b1be9afb8cfd98" + integrity sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw== + +"@babel/core@^7.11.6", "@babel/core@^7.12.3": + version "7.23.6" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.23.6.tgz#8be77cd77c55baadcc1eae1c33df90ab6d2151d4" + integrity sha512-FxpRyGjrMJXh7X3wGLGhNDCRiwpWEF74sKjTLDJSG5Kyvow3QZaG0Adbqzi9ZrVjTWpsX+2cxWXD71NMg93kdw== + dependencies: + "@ampproject/remapping" "^2.2.0" + "@babel/code-frame" "^7.23.5" + "@babel/generator" "^7.23.6" + "@babel/helper-compilation-targets" "^7.23.6" + "@babel/helper-module-transforms" "^7.23.3" + "@babel/helpers" "^7.23.6" + "@babel/parser" "^7.23.6" + "@babel/template" "^7.22.15" + "@babel/traverse" "^7.23.6" + "@babel/types" "^7.23.6" + convert-source-map "^2.0.0" + debug "^4.1.0" + gensync "^1.0.0-beta.2" + json5 "^2.2.3" + semver "^6.3.1" + +"@babel/generator@^7.23.6", "@babel/generator@^7.7.2": + version "7.23.6" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.6.tgz#9e1fca4811c77a10580d17d26b57b036133f3c2e" + integrity sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw== + dependencies: + "@babel/types" "^7.23.6" + "@jridgewell/gen-mapping" "^0.3.2" + "@jridgewell/trace-mapping" "^0.3.17" + jsesc "^2.5.1" + +"@babel/helper-compilation-targets@^7.23.6": + version "7.23.6" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz#4d79069b16cbcf1461289eccfbbd81501ae39991" + integrity sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ== + dependencies: + "@babel/compat-data" "^7.23.5" + "@babel/helper-validator-option" "^7.23.5" + browserslist "^4.22.2" + lru-cache "^5.1.1" + semver "^6.3.1" + +"@babel/helper-environment-visitor@^7.22.20": + version "7.22.20" + resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167" + integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA== + +"@babel/helper-function-name@^7.23.0": + version "7.23.0" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz#1f9a3cdbd5b2698a670c30d2735f9af95ed52759" + integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw== + dependencies: + "@babel/template" "^7.22.15" + "@babel/types" "^7.23.0" + +"@babel/helper-hoist-variables@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb" + integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-module-imports@^7.22.15": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz#16146307acdc40cc00c3b2c647713076464bdbf0" + integrity sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w== + dependencies: + "@babel/types" "^7.22.15" + +"@babel/helper-module-transforms@^7.23.3": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz#d7d12c3c5d30af5b3c0fcab2a6d5217773e2d0f1" + integrity sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ== + dependencies: + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-module-imports" "^7.22.15" + "@babel/helper-simple-access" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + "@babel/helper-validator-identifier" "^7.22.20" + +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.22.5", "@babel/helper-plugin-utils@^7.8.0": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz#dd7ee3735e8a313b9f7b05a773d892e88e6d7295" + integrity sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg== + +"@babel/helper-simple-access@^7.22.5": + version "7.22.5" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz#4938357dc7d782b80ed6dbb03a0fba3d22b1d5de" + integrity sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-split-export-declaration@^7.22.6": + version "7.22.6" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c" + integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g== + dependencies: + "@babel/types" "^7.22.5" + +"@babel/helper-string-parser@^7.23.4": + version "7.23.4" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz#9478c707febcbbe1ddb38a3d91a2e054ae622d83" + integrity sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ== + +"@babel/helper-validator-identifier@^7.22.20": + version "7.22.20" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0" + integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A== + +"@babel/helper-validator-option@^7.23.5": + version "7.23.5" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz#907a3fbd4523426285365d1206c423c4c5520307" + integrity sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw== + +"@babel/helpers@^7.23.6": + version "7.23.6" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.23.6.tgz#d03af2ee5fb34691eec0cda90f5ecbb4d4da145a" + integrity sha512-wCfsbN4nBidDRhpDhvcKlzHWCTlgJYUUdSJfzXb2NuBssDSIjc3xcb+znA7l+zYsFljAcGM0aFkN40cR3lXiGA== + dependencies: + "@babel/template" "^7.22.15" + "@babel/traverse" "^7.23.6" + "@babel/types" "^7.23.6" + +"@babel/highlight@^7.23.4": + version "7.23.4" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.23.4.tgz#edaadf4d8232e1a961432db785091207ead0621b" + integrity sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A== + dependencies: + "@babel/helper-validator-identifier" "^7.22.20" + chalk "^2.4.2" + js-tokens "^4.0.0" + +"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.20.7", "@babel/parser@^7.22.15", "@babel/parser@^7.23.6": + version "7.23.6" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.6.tgz#ba1c9e512bda72a47e285ae42aff9d2a635a9e3b" + integrity sha512-Z2uID7YJ7oNvAI20O9X0bblw7Qqs8Q2hFy0R9tAfnfLkp5MW0UH9eUvnDSnFwKZ0AvgS1ucqR4KzvVHgnke1VQ== + +"@babel/plugin-syntax-async-generators@^7.8.4": + version "7.8.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-bigint@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea" + integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-class-properties@^7.8.3": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" + integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== + dependencies: + "@babel/helper-plugin-utils" "^7.12.13" + +"@babel/plugin-syntax-import-meta@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" + integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-json-strings@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-jsx@^7.7.2": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.23.3.tgz#8f2e4f8a9b5f9aa16067e142c1ac9cd9f810f473" + integrity sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/plugin-syntax-logical-assignment-operators@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" + integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-numeric-separator@^7.8.3": + version "7.10.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" + integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== + dependencies: + "@babel/helper-plugin-utils" "^7.10.4" + +"@babel/plugin-syntax-object-rest-spread@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-catch-binding@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-optional-chaining@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-top-level-await@^7.8.3": + version "7.14.5" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" + integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== + dependencies: + "@babel/helper-plugin-utils" "^7.14.5" + +"@babel/plugin-syntax-typescript@^7.7.2": + version "7.23.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.23.3.tgz#24f460c85dbbc983cd2b9c4994178bcc01df958f" + integrity sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ== + dependencies: + "@babel/helper-plugin-utils" "^7.22.5" + +"@babel/template@^7.22.15", "@babel/template@^7.3.3": + version "7.22.15" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.15.tgz#09576efc3830f0430f4548ef971dde1350ef2f38" + integrity sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w== + dependencies: + "@babel/code-frame" "^7.22.13" + "@babel/parser" "^7.22.15" + "@babel/types" "^7.22.15" + +"@babel/traverse@^7.23.6": + version "7.23.6" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.6.tgz#b53526a2367a0dd6edc423637f3d2d0f2521abc5" + integrity sha512-czastdK1e8YByZqezMPFiZ8ahwVMh/ESl9vPgvgdB9AmFMGP5jfpFax74AQgl5zj4XHzqeYAg2l8PuUeRS1MgQ== + dependencies: + "@babel/code-frame" "^7.23.5" + "@babel/generator" "^7.23.6" + "@babel/helper-environment-visitor" "^7.22.20" + "@babel/helper-function-name" "^7.23.0" + "@babel/helper-hoist-variables" "^7.22.5" + "@babel/helper-split-export-declaration" "^7.22.6" + "@babel/parser" "^7.23.6" + "@babel/types" "^7.23.6" + debug "^4.3.1" + globals "^11.1.0" + +"@babel/types@^7.0.0", "@babel/types@^7.20.7", "@babel/types@^7.22.15", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.23.6", "@babel/types@^7.3.3": + version "7.23.6" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.6.tgz#be33fdb151e1f5a56877d704492c240fc71c7ccd" + integrity sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg== + dependencies: + "@babel/helper-string-parser" "^7.23.4" + "@babel/helper-validator-identifier" "^7.22.20" + to-fast-properties "^2.0.0" + +"@bcoe/v8-coverage@^0.2.3": + version "0.2.3" + resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" + integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== + +"@colors/colors@1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9" + integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ== + +"@cspotcode/source-map-consumer@0.8.0": + version "0.8.0" + resolved "https://registry.yarnpkg.com/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz#33bf4b7b39c178821606f669bbc447a6a629786b" + integrity sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg== + +"@cspotcode/source-map-support@0.7.0": + version "0.7.0" + resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz#4789840aa859e46d2f3173727ab707c66bf344f5" + integrity sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA== + dependencies: + "@cspotcode/source-map-consumer" "0.8.0" + +"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": + version "4.4.0" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" + integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== + dependencies: + eslint-visitor-keys "^3.3.0" + +"@eslint-community/regexpp@^4.10.0", "@eslint-community/regexpp@^4.12.1": + version "4.12.1" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.12.1.tgz#cfc6cffe39df390a3841cde2abccf92eaa7ae0e0" + integrity sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ== + +"@eslint/config-array@^0.19.0": + version "0.19.2" + resolved "https://registry.yarnpkg.com/@eslint/config-array/-/config-array-0.19.2.tgz#3060b809e111abfc97adb0bb1172778b90cb46aa" + integrity sha512-GNKqxfHG2ySmJOBSHg7LxeUx4xpuCoFjacmlCoYWEbaPXLwvfIjixRI12xCQZeULksQb23uiA8F40w5TojpV7w== + dependencies: + "@eslint/object-schema" "^2.1.6" + debug "^4.3.1" + minimatch "^3.1.2" + +"@eslint/core@^0.10.0": + version "0.10.0" + resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.10.0.tgz#23727063c21b335f752dbb3a16450f6f9cbc9091" + integrity sha512-gFHJ+xBOo4G3WRlR1e/3G8A6/KZAH6zcE/hkLRCZTi/B9avAG365QhFA8uOGzTMqgTghpn7/fSnscW++dpMSAw== + dependencies: + "@types/json-schema" "^7.0.15" + +"@eslint/core@^0.11.0": + version "0.11.0" + resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.11.0.tgz#7a9226e850922e42cbd2ba71361eacbe74352a12" + integrity sha512-DWUB2pksgNEb6Bz2fggIy1wh6fGgZP4Xyy/Mt0QZPiloKKXerbqq9D3SBQTlCRYOrcRPu4vuz+CGjwdfqxnoWA== + dependencies: + "@types/json-schema" "^7.0.15" + +"@eslint/eslintrc@^3.2.0": + version "3.2.0" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.2.0.tgz#57470ac4e2e283a6bf76044d63281196e370542c" + integrity sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^10.0.1" + globals "^14.0.0" + ignore "^5.2.0" + import-fresh "^3.2.1" + js-yaml "^4.1.0" + minimatch "^3.1.2" + strip-json-comments "^3.1.1" + +"@eslint/js@9.20.0": + version "9.20.0" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.20.0.tgz#7421bcbe74889fcd65d1be59f00130c289856eb4" + integrity sha512-iZA07H9io9Wn836aVTytRaNqh00Sad+EamwOVJT12GTLw1VGMFV/4JaME+JjLtr9fiGaoWgYnS54wrfWsSs4oQ== + +"@eslint/object-schema@^2.1.6": + version "2.1.6" + resolved "https://registry.yarnpkg.com/@eslint/object-schema/-/object-schema-2.1.6.tgz#58369ab5b5b3ca117880c0f6c0b0f32f6950f24f" + integrity sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA== + +"@eslint/plugin-kit@^0.2.5": + version "0.2.5" + resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.2.5.tgz#ee07372035539e7847ef834e3f5e7b79f09e3a81" + integrity sha512-lB05FkqEdUg2AA0xEbUz0SnkXT1LcCTa438W4IWTUh4hdOnVbQyOJ81OrDXsJk/LSiJHubgGEFoR5EHq1NsH1A== + dependencies: + "@eslint/core" "^0.10.0" + levn "^0.4.1" + +"@humanfs/core@^0.19.1": + version "0.19.1" + resolved "https://registry.yarnpkg.com/@humanfs/core/-/core-0.19.1.tgz#17c55ca7d426733fe3c561906b8173c336b40a77" + integrity sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA== + +"@humanfs/node@^0.16.6": + version "0.16.6" + resolved "https://registry.yarnpkg.com/@humanfs/node/-/node-0.16.6.tgz#ee2a10eaabd1131987bf0488fd9b820174cd765e" + integrity sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw== + dependencies: + "@humanfs/core" "^0.19.1" + "@humanwhocodes/retry" "^0.3.0" + +"@humanwhocodes/module-importer@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" + integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== + +"@humanwhocodes/retry@^0.3.0": + version "0.3.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.3.1.tgz#c72a5c76a9fbaf3488e231b13dc52c0da7bab42a" + integrity sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA== + +"@humanwhocodes/retry@^0.4.1": + version "0.4.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.4.1.tgz#9a96ce501bc62df46c4031fbd970e3cc6b10f07b" + integrity sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA== + +"@istanbuljs/load-nyc-config@^1.0.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" + integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== + dependencies: + camelcase "^5.3.1" + find-up "^4.1.0" + get-package-type "^0.1.0" + js-yaml "^3.13.1" + resolve-from "^5.0.0" + +"@istanbuljs/schema@^0.1.2": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" + integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== + +"@jest/console@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-29.7.0.tgz#cd4822dbdb84529265c5a2bdb529a3c9cc950ffc" + integrity sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg== + dependencies: + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + slash "^3.0.0" + +"@jest/core@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-29.7.0.tgz#b6cccc239f30ff36609658c5a5e2291757ce448f" + integrity sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg== + dependencies: + "@jest/console" "^29.7.0" + "@jest/reporters" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + ci-info "^3.2.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + jest-changed-files "^29.7.0" + jest-config "^29.7.0" + jest-haste-map "^29.7.0" + jest-message-util "^29.7.0" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-resolve-dependencies "^29.7.0" + jest-runner "^29.7.0" + jest-runtime "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" + jest-watcher "^29.7.0" + micromatch "^4.0.4" + pretty-format "^29.7.0" + slash "^3.0.0" + strip-ansi "^6.0.0" + +"@jest/create-cache-key-function@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/create-cache-key-function/-/create-cache-key-function-29.7.0.tgz#793be38148fab78e65f40ae30c36785f4ad859f0" + integrity sha512-4QqS3LY5PBmTRHj9sAg1HLoPzqAI0uOX6wI/TRqHIcOxlFidy6YEmCQJk6FSZjNLGCeubDMfmkWL+qaLKhSGQA== + dependencies: + "@jest/types" "^29.6.3" + +"@jest/environment@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-29.7.0.tgz#24d61f54ff1f786f3cd4073b4b94416383baf2a7" + integrity sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw== + dependencies: + "@jest/fake-timers" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + jest-mock "^29.7.0" + +"@jest/expect-utils@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.7.0.tgz#023efe5d26a8a70f21677d0a1afc0f0a44e3a1c6" + integrity sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA== + dependencies: + jest-get-type "^29.6.3" + +"@jest/expect@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-29.7.0.tgz#76a3edb0cb753b70dfbfe23283510d3d45432bf2" + integrity sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ== + dependencies: + expect "^29.7.0" + jest-snapshot "^29.7.0" + +"@jest/fake-timers@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-29.7.0.tgz#fd91bf1fffb16d7d0d24a426ab1a47a49881a565" + integrity sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ== + dependencies: + "@jest/types" "^29.6.3" + "@sinonjs/fake-timers" "^10.0.2" + "@types/node" "*" + jest-message-util "^29.7.0" + jest-mock "^29.7.0" + jest-util "^29.7.0" + +"@jest/globals@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-29.7.0.tgz#8d9290f9ec47ff772607fa864ca1d5a2efae1d4d" + integrity sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/expect" "^29.7.0" + "@jest/types" "^29.6.3" + jest-mock "^29.7.0" + +"@jest/reporters@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-29.7.0.tgz#04b262ecb3b8faa83b0b3d321623972393e8f4c7" + integrity sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg== + dependencies: + "@bcoe/v8-coverage" "^0.2.3" + "@jest/console" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@jridgewell/trace-mapping" "^0.3.18" + "@types/node" "*" + chalk "^4.0.0" + collect-v8-coverage "^1.0.0" + exit "^0.1.2" + glob "^7.1.3" + graceful-fs "^4.2.9" + istanbul-lib-coverage "^3.0.0" + istanbul-lib-instrument "^6.0.0" + istanbul-lib-report "^3.0.0" + istanbul-lib-source-maps "^4.0.0" + istanbul-reports "^3.1.3" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + jest-worker "^29.7.0" + slash "^3.0.0" + string-length "^4.0.1" + strip-ansi "^6.0.0" + v8-to-istanbul "^9.0.1" + +"@jest/schemas@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.6.3.tgz#430b5ce8a4e0044a7e3819663305a7b3091c8e03" + integrity sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA== + dependencies: + "@sinclair/typebox" "^0.27.8" + +"@jest/source-map@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-29.6.3.tgz#d90ba772095cf37a34a5eb9413f1b562a08554c4" + integrity sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw== + dependencies: + "@jridgewell/trace-mapping" "^0.3.18" + callsites "^3.0.0" + graceful-fs "^4.2.9" + +"@jest/test-result@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-29.7.0.tgz#8db9a80aa1a097bb2262572686734baed9b1657c" + integrity sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA== + dependencies: + "@jest/console" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/istanbul-lib-coverage" "^2.0.0" + collect-v8-coverage "^1.0.0" + +"@jest/test-sequencer@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz#6cef977ce1d39834a3aea887a1726628a6f072ce" + integrity sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw== + dependencies: + "@jest/test-result" "^29.7.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + slash "^3.0.0" + +"@jest/transform@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-29.7.0.tgz#df2dd9c346c7d7768b8a06639994640c642e284c" + integrity sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw== + dependencies: + "@babel/core" "^7.11.6" + "@jest/types" "^29.6.3" + "@jridgewell/trace-mapping" "^0.3.18" + babel-plugin-istanbul "^6.1.1" + chalk "^4.0.0" + convert-source-map "^2.0.0" + fast-json-stable-stringify "^2.1.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + jest-regex-util "^29.6.3" + jest-util "^29.7.0" + micromatch "^4.0.4" + pirates "^4.0.4" + slash "^3.0.0" + write-file-atomic "^4.0.2" + +"@jest/types@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.6.3.tgz#1131f8cf634e7e84c5e77bab12f052af585fba59" + integrity sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw== + dependencies: + "@jest/schemas" "^29.6.3" + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^17.0.8" + chalk "^4.0.0" + +"@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz#7e02e6eb5df901aaedb08514203b096614024098" + integrity sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ== + dependencies: + "@jridgewell/set-array" "^1.0.1" + "@jridgewell/sourcemap-codec" "^1.4.10" + "@jridgewell/trace-mapping" "^0.3.9" + +"@jridgewell/resolve-uri@^3.1.0": + version "3.1.1" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz#c08679063f279615a3326583ba3a90d1d82cc721" + integrity sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA== + +"@jridgewell/set-array@^1.0.1": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" + integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== + +"@jridgewell/sourcemap-codec@^1.4.10", "@jridgewell/sourcemap-codec@^1.4.14": + version "1.4.15" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" + integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== + +"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.9": + version "0.3.20" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz#72e45707cf240fa6b081d0366f8265b0cd10197f" + integrity sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@pkgr/core@^0.1.0": + version "0.1.1" + resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.1.1.tgz#1ec17e2edbec25c8306d424ecfbf13c7de1aaa31" + integrity sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA== + +"@sinclair/typebox@^0.27.8": + version "0.27.8" + resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" + integrity sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA== + +"@sindresorhus/is@^4.6.0": + version "4.6.0" + resolved "https://registry.yarnpkg.com/@sindresorhus/is/-/is-4.6.0.tgz#3c7c9c46e678feefe7a2e5bb609d3dbd665ffb3f" + integrity sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw== + +"@sinonjs/commons@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-3.0.0.tgz#beb434fe875d965265e04722ccfc21df7f755d72" + integrity sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA== + dependencies: + type-detect "4.0.8" + +"@sinonjs/fake-timers@^10.0.2": + version "10.3.0" + resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz#55fdff1ecab9f354019129daf4df0dd4d923ea66" + integrity sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA== + dependencies: + "@sinonjs/commons" "^3.0.0" + +"@swc/core-darwin-arm64@1.4.16": + version "1.4.16" + resolved "https://registry.yarnpkg.com/@swc/core-darwin-arm64/-/core-darwin-arm64-1.4.16.tgz#2cd45d709ce76d448d96bf8d0006849541436611" + integrity sha512-UOCcH1GvjRnnM/LWT6VCGpIk0OhHRq6v1U6QXuPt5wVsgXnXQwnf5k3sG5Cm56hQHDvhRPY6HCsHi/p0oek8oQ== + +"@swc/core-darwin-x64@1.4.16": + version "1.4.16" + resolved "https://registry.yarnpkg.com/@swc/core-darwin-x64/-/core-darwin-x64-1.4.16.tgz#a5bc7d8b1dd850adb0bb95c6b5c742b92201fd01" + integrity sha512-t3bgqFoYLWvyVtVL6KkFNCINEoOrIlyggT/kJRgi1y0aXSr0oVgcrQ4ezJpdeahZZ4N+Q6vT3ffM30yIunELNA== + +"@swc/core-linux-arm-gnueabihf@1.4.16": + version "1.4.16" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.4.16.tgz#961744908ee5cbb79bc009dcf58cc8b831111f38" + integrity sha512-DvHuwvEF86YvSd0lwnzVcjOTZ0jcxewIbsN0vc/0fqm9qBdMMjr9ox6VCam1n3yYeRtj4VFgrjeNFksqbUejdQ== + +"@swc/core-linux-arm64-gnu@1.4.16": + version "1.4.16" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.4.16.tgz#43713be3f26757d82d2745dc25f8b63400e0a3d0" + integrity sha512-9Uu5YlPbyCvbidjKtYEsPpyZlu16roOZ5c2tP1vHfnU9bgf5Tz5q5VovSduNxPHx+ed2iC1b1URODHvDzbbDuQ== + +"@swc/core-linux-arm64-musl@1.4.16": + version "1.4.16" + resolved "https://registry.yarnpkg.com/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.4.16.tgz#394a7d030f3a61902bd3947bb9d70d26d42f3c81" + integrity sha512-/YZq/qB1CHpeoL0eMzyqK5/tYZn/rzKoCYDviFU4uduSUIJsDJQuQA/skdqUzqbheOXKAd4mnJ1hT04RbJ8FPQ== + +"@swc/core-linux-x64-gnu@1.4.16": + version "1.4.16" + resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.4.16.tgz#71eb108b784f9d551ee8a35ebcdaed972f567981" + integrity sha512-UUjaW5VTngZYDcA8yQlrFmqs1tLi1TxbKlnaJwoNhel9zRQ0yG1YEVGrzTvv4YApSuIiDK18t+Ip927bwucuVQ== + +"@swc/core-linux-x64-musl@1.4.16": + version "1.4.16" + resolved "https://registry.yarnpkg.com/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.4.16.tgz#10dbaedb4e3dfc7268e3a9a66ad3431471ef035b" + integrity sha512-aFhxPifevDTwEDKPi4eRYWzC0p/WYJeiFkkpNU5Uc7a7M5iMWPAbPFUbHesdlb9Jfqs5c07oyz86u+/HySBNPQ== + +"@swc/core-win32-arm64-msvc@1.4.16": + version "1.4.16" + resolved "https://registry.yarnpkg.com/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.4.16.tgz#80247adff6c245ff32b44d773c1a148858cd655f" + integrity sha512-bTD43MbhIHL2s5QgCwyleaGwl96Gk/scF2TaVKdUe4QlJCDV/YK9h5oIBAp63ckHtE8GHlH4c8dZNBiAXn4Org== + +"@swc/core-win32-ia32-msvc@1.4.16": + version "1.4.16" + resolved "https://registry.yarnpkg.com/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.4.16.tgz#e540afc3ccf3224267b4ddfb408f9d9737984686" + integrity sha512-/lmZeAN/qV5XbK2SEvi8e2RkIg8FQNYiSA8y2/Zb4gTUMKVO5JMLH0BSWMiIKMstKDPDSxMWgwJaQHF8UMyPmQ== + +"@swc/core-win32-x64-msvc@1.4.16": + version "1.4.16" + resolved "https://registry.yarnpkg.com/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.4.16.tgz#f880939fca32c181adfe7e3abd2b6b7857bd3489" + integrity sha512-BPAfFfODWXtUu6SwaTTftDHvcbDyWBSI/oanUeRbQR5vVWkXoQ3cxLTsDluc3H74IqXS5z1Uyoe0vNo2hB1opA== + +"@swc/core@^1.3.102": + version "1.4.16" + resolved "https://registry.yarnpkg.com/@swc/core/-/core-1.4.16.tgz#d175bae2acfecd53bcbd4293f1fba5ec316634a0" + integrity sha512-Xaf+UBvW6JNuV131uvSNyMXHn+bh6LyKN4tbv7tOUFQpXyz/t9YWRE04emtlUW9Y0qrm/GKFCbY8n3z6BpZbTA== + dependencies: + "@swc/counter" "^0.1.2" + "@swc/types" "^0.1.5" + optionalDependencies: + "@swc/core-darwin-arm64" "1.4.16" + "@swc/core-darwin-x64" "1.4.16" + "@swc/core-linux-arm-gnueabihf" "1.4.16" + "@swc/core-linux-arm64-gnu" "1.4.16" + "@swc/core-linux-arm64-musl" "1.4.16" + "@swc/core-linux-x64-gnu" "1.4.16" + "@swc/core-linux-x64-musl" "1.4.16" + "@swc/core-win32-arm64-msvc" "1.4.16" + "@swc/core-win32-ia32-msvc" "1.4.16" + "@swc/core-win32-x64-msvc" "1.4.16" + +"@swc/counter@^0.1.2", "@swc/counter@^0.1.3": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@swc/counter/-/counter-0.1.3.tgz#cc7463bd02949611c6329596fccd2b0ec782b0e9" + integrity sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ== + +"@swc/jest@^0.2.29": + version "0.2.36" + resolved "https://registry.yarnpkg.com/@swc/jest/-/jest-0.2.36.tgz#2797450a30d28b471997a17e901ccad946fe693e" + integrity sha512-8X80dp81ugxs4a11z1ka43FPhP+/e+mJNXJSxiNYk8gIX/jPBtY4gQTrKu/KIoco8bzKuPI5lUxjfLiGsfvnlw== + dependencies: + "@jest/create-cache-key-function" "^29.7.0" + "@swc/counter" "^0.1.3" + jsonc-parser "^3.2.0" + +"@swc/types@^0.1.5": + version "0.1.6" + resolved "https://registry.yarnpkg.com/@swc/types/-/types-0.1.6.tgz#2f13f748995b247d146de2784d3eb7195410faba" + integrity sha512-/JLo/l2JsT/LRd80C3HfbmVpxOAJ11FO2RCEslFrgzLltoP9j8XIbsyDcfCt2WWyX+CM96rBoNM+IToAkFOugg== + dependencies: + "@swc/counter" "^0.1.3" + +"@tsconfig/node10@^1.0.7": + version "1.0.8" + resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.8.tgz#c1e4e80d6f964fbecb3359c43bd48b40f7cadad9" + integrity sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg== + +"@tsconfig/node12@^1.0.7": + version "1.0.9" + resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.9.tgz#62c1f6dee2ebd9aead80dc3afa56810e58e1a04c" + integrity sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw== + +"@tsconfig/node14@^1.0.0": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.1.tgz#95f2d167ffb9b8d2068b0b235302fafd4df711f2" + integrity sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg== + +"@tsconfig/node16@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.2.tgz#423c77877d0569db20e1fc80885ac4118314010e" + integrity sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA== + +"@types/babel__core@^7.1.14": + version "7.20.5" + resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.5.tgz#3df15f27ba85319caa07ba08d0721889bb39c017" + integrity sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA== + dependencies: + "@babel/parser" "^7.20.7" + "@babel/types" "^7.20.7" + "@types/babel__generator" "*" + "@types/babel__template" "*" + "@types/babel__traverse" "*" + +"@types/babel__generator@*": + version "7.6.8" + resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.8.tgz#f836c61f48b1346e7d2b0d93c6dacc5b9535d3ab" + integrity sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw== + dependencies: + "@babel/types" "^7.0.0" + +"@types/babel__template@*": + version "7.4.4" + resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.4.4.tgz#5672513701c1b2199bc6dad636a9d7491586766f" + integrity sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A== + dependencies: + "@babel/parser" "^7.1.0" + "@babel/types" "^7.0.0" + +"@types/babel__traverse@*", "@types/babel__traverse@^7.0.6": + version "7.20.4" + resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.20.4.tgz#ec2c06fed6549df8bc0eb4615b683749a4a92e1b" + integrity sha512-mSM/iKUk5fDDrEV/e83qY+Cr3I1+Q3qqTuEn++HAWYjEa1+NxZr6CNrcJGf2ZTnq4HoFGC3zaTPZTobCzCFukA== + dependencies: + "@babel/types" "^7.20.7" + +"@types/estree@^1.0.6": + version "1.0.6" + resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.6.tgz#628effeeae2064a1b4e79f78e81d87b7e5fc7b50" + integrity sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw== + +"@types/graceful-fs@^4.1.3": + version "4.1.9" + resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.9.tgz#2a06bc0f68a20ab37b3e36aa238be6abdf49e8b4" + integrity sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ== + dependencies: + "@types/node" "*" + +"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": + version "2.0.6" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz#7739c232a1fee9b4d3ce8985f314c0c6d33549d7" + integrity sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w== + +"@types/istanbul-lib-report@*": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz#53047614ae72e19fc0401d872de3ae2b4ce350bf" + integrity sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA== + dependencies: + "@types/istanbul-lib-coverage" "*" + +"@types/istanbul-reports@^3.0.0": + version "3.0.4" + resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz#0f03e3d2f670fbdac586e34b433783070cc16f54" + integrity sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ== + dependencies: + "@types/istanbul-lib-report" "*" + +"@types/jest@^29.4.0": + version "29.5.11" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.11.tgz#0c13aa0da7d0929f078ab080ae5d4ced80fa2f2c" + integrity sha512-S2mHmYIVe13vrm6q4kN6fLYYAka15ALQki/vgDC3mIukEOx8WJlv0kQPM+d4w8Gp6u0uSdKND04IlTXBv0rwnQ== + dependencies: + expect "^29.0.0" + pretty-format "^29.0.0" + +"@types/json-schema@^7.0.15": + version "7.0.15" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" + integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== + +"@types/node@*": + version "20.10.5" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.10.5.tgz#47ad460b514096b7ed63a1dae26fad0914ed3ab2" + integrity sha512-nNPsNE65wjMxEKI93yOP+NPGGBJz/PoN3kZsVLee0XMiJolxSekEVD8wRwBUBqkwc7UWop0edW50yrCQW4CyRw== + dependencies: + undici-types "~5.26.4" + +"@types/node@^20.17.6": + version "20.17.6" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.17.6.tgz#6e4073230c180d3579e8c60141f99efdf5df0081" + integrity sha512-VEI7OdvK2wP7XHnsuXbAJnEpEkF6NjSN45QJlL4VGqZSXsnicpesdTWsg9RISeSdYd3yeRj/y3k5KGjUXYnFwQ== + dependencies: + undici-types "~6.19.2" + +"@types/stack-utils@^2.0.0": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.3.tgz#6209321eb2c1712a7e7466422b8cb1fc0d9dd5d8" + integrity sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw== + +"@types/yargs-parser@*": + version "21.0.3" + resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.3.tgz#815e30b786d2e8f0dcd85fd5bcf5e1a04d008f15" + integrity sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ== + +"@types/yargs@^17.0.8": + version "17.0.32" + resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-17.0.32.tgz#030774723a2f7faafebf645f4e5a48371dca6229" + integrity sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog== + dependencies: + "@types/yargs-parser" "*" + +"@typescript-eslint/eslint-plugin@8.31.1": + version "8.31.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.31.1.tgz#62f1befe59647524994e89de4516d8dcba7a850a" + integrity sha512-oUlH4h1ABavI4F0Xnl8/fOtML/eu8nI2A1nYd+f+55XI0BLu+RIqKoCiZKNo6DtqZBEQm5aNKA20G3Z5w3R6GQ== + dependencies: + "@eslint-community/regexpp" "^4.10.0" + "@typescript-eslint/scope-manager" "8.31.1" + "@typescript-eslint/type-utils" "8.31.1" + "@typescript-eslint/utils" "8.31.1" + "@typescript-eslint/visitor-keys" "8.31.1" + graphemer "^1.4.0" + ignore "^5.3.1" + natural-compare "^1.4.0" + ts-api-utils "^2.0.1" + +"@typescript-eslint/parser@8.31.1": + version "8.31.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.31.1.tgz#e9b0ccf30d37dde724ee4d15f4dbc195995cce1b" + integrity sha512-oU/OtYVydhXnumd0BobL9rkJg7wFJ9bFFPmSmB/bf/XWN85hlViji59ko6bSKBXyseT9V8l+CN1nwmlbiN0G7Q== + dependencies: + "@typescript-eslint/scope-manager" "8.31.1" + "@typescript-eslint/types" "8.31.1" + "@typescript-eslint/typescript-estree" "8.31.1" + "@typescript-eslint/visitor-keys" "8.31.1" + debug "^4.3.4" + +"@typescript-eslint/scope-manager@8.31.1": + version "8.31.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.31.1.tgz#1eb52e76878f545e4add142e0d8e3e97e7aa443b" + integrity sha512-BMNLOElPxrtNQMIsFHE+3P0Yf1z0dJqV9zLdDxN/xLlWMlXK/ApEsVEKzpizg9oal8bAT5Sc7+ocal7AC1HCVw== + dependencies: + "@typescript-eslint/types" "8.31.1" + "@typescript-eslint/visitor-keys" "8.31.1" + +"@typescript-eslint/type-utils@8.31.1": + version "8.31.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.31.1.tgz#be0f438fb24b03568e282a0aed85f776409f970c" + integrity sha512-fNaT/m9n0+dpSp8G/iOQ05GoHYXbxw81x+yvr7TArTuZuCA6VVKbqWYVZrV5dVagpDTtj/O8k5HBEE/p/HM5LA== + dependencies: + "@typescript-eslint/typescript-estree" "8.31.1" + "@typescript-eslint/utils" "8.31.1" + debug "^4.3.4" + ts-api-utils "^2.0.1" + +"@typescript-eslint/types@8.31.1": + version "8.31.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.31.1.tgz#478ed6f7e8aee1be7b63a60212b6bffe1423b5d4" + integrity sha512-SfepaEFUDQYRoA70DD9GtytljBePSj17qPxFHA/h3eg6lPTqGJ5mWOtbXCk1YrVU1cTJRd14nhaXWFu0l2troQ== + +"@typescript-eslint/typescript-estree@8.31.1": + version "8.31.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.31.1.tgz#37792fe7ef4d3021c7580067c8f1ae66daabacdf" + integrity sha512-kaA0ueLe2v7KunYOyWYtlf/QhhZb7+qh4Yw6Ni5kgukMIG+iP773tjgBiLWIXYumWCwEq3nLW+TUywEp8uEeag== + dependencies: + "@typescript-eslint/types" "8.31.1" + "@typescript-eslint/visitor-keys" "8.31.1" + debug "^4.3.4" + fast-glob "^3.3.2" + is-glob "^4.0.3" + minimatch "^9.0.4" + semver "^7.6.0" + ts-api-utils "^2.0.1" + +"@typescript-eslint/utils@8.31.1": + version "8.31.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.31.1.tgz#5628ea0393598a0b2f143d0fc6d019f0dee9dd14" + integrity sha512-2DSI4SNfF5T4oRveQ4nUrSjUqjMND0nLq9rEkz0gfGr3tg0S5KB6DhwR+WZPCjzkZl3cH+4x2ce3EsL50FubjQ== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + "@typescript-eslint/scope-manager" "8.31.1" + "@typescript-eslint/types" "8.31.1" + "@typescript-eslint/typescript-estree" "8.31.1" + +"@typescript-eslint/visitor-keys@8.31.1": + version "8.31.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.31.1.tgz#6742b0e3ba1e0c1e35bdaf78c03e759eb8dd8e75" + integrity sha512-I+/rgqOVBn6f0o7NDTmAPWWC6NuqhV174lfYvAm9fUaWeiefLdux9/YI3/nLugEn9L8fcSi0XmpKi/r5u0nmpw== + dependencies: + "@typescript-eslint/types" "8.31.1" + eslint-visitor-keys "^4.2.0" + +acorn-jsx@^5.3.2: + version "5.3.2" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +acorn-walk@^8.1.1: + version "8.2.0" + resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" + integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== + +acorn@^8.14.0: + version "8.14.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.0.tgz#063e2c70cac5fb4f6467f0b11152e04c682795b0" + integrity sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA== + +acorn@^8.4.1: + version "8.7.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.0.tgz#90951fde0f8f09df93549481e5fc141445b791cf" + integrity sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ== + +aggregate-error@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" + integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== + dependencies: + clean-stack "^2.0.0" + indent-string "^4.0.0" + +ajv@^6.12.4: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +ansi-escapes@^4.2.1: + version "4.3.2" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" + integrity sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ== + dependencies: + type-fest "^0.21.3" + +ansi-escapes@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-7.0.0.tgz#00fc19f491bbb18e1d481b97868204f92109bfe7" + integrity sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw== + dependencies: + environment "^1.0.0" + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-regex@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-6.1.0.tgz#95ec409c69619d6cb1b8b34f14b660ef28ebd654" + integrity sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA== + +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +ansi-styles@^5.0.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-5.2.0.tgz#07449690ad45777d1924ac2abb2fc8895dba836b" + integrity sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA== + +any-promise@^1.0.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" + integrity sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A== + +anymatch@^3.0.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +arg@^4.1.0: + version "4.1.3" + resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089" + integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA== + +argparse@^1.0.7: + version "1.0.10" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== + dependencies: + sprintf-js "~1.0.2" + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +babel-jest@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.7.0.tgz#f4369919225b684c56085998ac63dbd05be020d5" + integrity sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg== + dependencies: + "@jest/transform" "^29.7.0" + "@types/babel__core" "^7.1.14" + babel-plugin-istanbul "^6.1.1" + babel-preset-jest "^29.6.3" + chalk "^4.0.0" + graceful-fs "^4.2.9" + slash "^3.0.0" + +babel-plugin-istanbul@^6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz#fa88ec59232fd9b4e36dbbc540a8ec9a9b47da73" + integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA== + dependencies: + "@babel/helper-plugin-utils" "^7.0.0" + "@istanbuljs/load-nyc-config" "^1.0.0" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-instrument "^5.0.4" + test-exclude "^6.0.0" + +babel-plugin-jest-hoist@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz#aadbe943464182a8922c3c927c3067ff40d24626" + integrity sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg== + dependencies: + "@babel/template" "^7.3.3" + "@babel/types" "^7.3.3" + "@types/babel__core" "^7.1.14" + "@types/babel__traverse" "^7.0.6" + +babel-preset-current-node-syntax@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz#b4399239b89b2a011f9ddbe3e4f401fc40cff73b" + integrity sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ== + dependencies: + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-bigint" "^7.8.3" + "@babel/plugin-syntax-class-properties" "^7.8.3" + "@babel/plugin-syntax-import-meta" "^7.8.3" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.8.3" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-top-level-await" "^7.8.3" + +babel-preset-jest@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz#fa05fa510e7d493896d7b0dd2033601c840f171c" + integrity sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA== + dependencies: + babel-plugin-jest-hoist "^29.6.3" + babel-preset-current-node-syntax "^1.0.0" + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + +braces@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== + dependencies: + fill-range "^7.1.1" + +browserslist@^4.22.2: + version "4.22.2" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.22.2.tgz#704c4943072bd81ea18997f3bd2180e89c77874b" + integrity sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A== + dependencies: + caniuse-lite "^1.0.30001565" + electron-to-chromium "^1.4.601" + node-releases "^2.0.14" + update-browserslist-db "^1.0.13" + +bs-logger@0.x: + version "0.2.6" + resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" + integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog== + dependencies: + fast-json-stable-stringify "2.x" + +bser@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" + integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== + dependencies: + node-int64 "^0.4.0" + +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +camelcase@^5.3.1: + version "5.3.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + +camelcase@^6.2.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + +caniuse-lite@^1.0.30001565: + version "1.0.30001570" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001570.tgz#b4e5c1fa786f733ab78fc70f592df6b3f23244ca" + integrity sha512-+3e0ASu4sw1SWaoCtvPeyXp+5PsjigkSt8OXZbF9StH5pQWbxEjLAZE3n8Aup5udop1uRiKA7a4utUk/uoSpUw== + +chalk@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^4.0.0, chalk@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chalk@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.3.0.tgz#67c20a7ebef70e7f3970a01f90fa210cb6860385" + integrity sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w== + +char-regex@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" + integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== + +ci-info@^3.2.0: + version "3.9.0" + resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" + integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== + +cjs-module-lexer@^1.0.0: + version "1.2.3" + resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz#6c370ab19f8a3394e318fe682686ec0ac684d107" + integrity sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ== + +cjs-module-lexer@^1.2.3: + version "1.4.1" + resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.4.1.tgz#707413784dbb3a72aa11c2f2b042a0bef4004170" + integrity sha512-cuSVIHi9/9E/+821Qjdvngor+xpnlwnuwIyZOaLmHBVdXL+gP+I6QQB9VkO7RI77YIcTV+S1W9AreJ5eN63JBA== + +clean-stack@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" + integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== + +cli-highlight@^2.1.11: + version "2.1.11" + resolved "https://registry.yarnpkg.com/cli-highlight/-/cli-highlight-2.1.11.tgz#49736fa452f0aaf4fae580e30acb26828d2dc1bf" + integrity sha512-9KDcoEVwyUXrjcJNvHD0NFc/hiwe/WPVYIleQh2O1N2Zro5gWJZ/K+3DGn8w8P/F6FxOgzyC5bxDyHIgCSPhGg== + dependencies: + chalk "^4.0.0" + highlight.js "^10.7.1" + mz "^2.4.0" + parse5 "^5.1.1" + parse5-htmlparser2-tree-adapter "^6.0.0" + yargs "^16.0.0" + +cli-table3@^0.6.3, cli-table3@^0.6.5: + version "0.6.5" + resolved "https://registry.yarnpkg.com/cli-table3/-/cli-table3-0.6.5.tgz#013b91351762739c16a9567c21a04632e449bf2f" + integrity sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ== + dependencies: + string-width "^4.2.0" + optionalDependencies: + "@colors/colors" "1.5.0" + +cliui@^7.0.2: + version "7.0.4" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + +cliui@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" + integrity sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.1" + wrap-ansi "^7.0.0" + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + integrity sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ== + +collect-v8-coverage@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz#c0b29bcd33bcd0779a1344c2136051e6afd3d9e9" + integrity sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q== + +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +commander@^10.0.1: + version "10.0.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-10.0.1.tgz#881ee46b4f77d1c1dccc5823433aa39b022cbe06" + integrity sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +convert-source-map@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" + integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== + +create-jest@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/create-jest/-/create-jest-29.7.0.tgz#a355c5b3cb1e1af02ba177fe7afd7feee49a5320" + integrity sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q== + dependencies: + "@jest/types" "^29.6.3" + chalk "^4.0.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + jest-config "^29.7.0" + jest-util "^29.7.0" + prompts "^2.0.1" + +create-require@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333" + integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== + +cross-spawn@^7.0.3, cross-spawn@^7.0.6: + version "7.0.6" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" + integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +debug@^4.3.4, debug@^4.3.7: + version "4.3.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.7.tgz#87945b4151a011d76d95a198d7111c865c360a52" + integrity sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ== + dependencies: + ms "^2.1.3" + +dedent@^1.0.0: + version "1.5.1" + resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.5.1.tgz#4f3fc94c8b711e9bb2800d185cd6ad20f2a90aff" + integrity sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg== + +deep-is@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== + +deepmerge@^4.2.2: + version "4.3.1" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" + integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== + +detect-newline@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" + integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== + +diff-sequences@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.6.3.tgz#4deaf894d11407c51efc8418012f9e70b84ea921" + integrity sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q== + +diff@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" + integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== + +electron-to-chromium@^1.4.601: + version "1.4.614" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.614.tgz#2fe789d61fa09cb875569f37c309d0c2701f91c0" + integrity sha512-X4ze/9Sc3QWs6h92yerwqv7aB/uU8vCjZcrMjA8N9R1pjMFRe44dLsck5FzLilOYvcXuDn93B+bpGYyufc70gQ== + +emittery@^0.13.1: + version "0.13.1" + resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.13.1.tgz#c04b8c3457490e0847ae51fced3af52d338e3dad" + integrity sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +emojilib@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/emojilib/-/emojilib-2.4.0.tgz#ac518a8bb0d5f76dda57289ccb2fdf9d39ae721e" + integrity sha512-5U0rVMU5Y2n2+ykNLQqMoqklN9ICBT/KsvC1Gz6vqHbz2AXXGkG+Pm5rMWk/8Vjrr/mY9985Hi8DYzn1F09Nyw== + +environment@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/environment/-/environment-1.1.0.tgz#8e86c66b180f363c7ab311787e0259665f45a9f1" + integrity sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q== + +error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== + dependencies: + is-arrayish "^0.2.1" + +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + +escape-string-regexp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" + integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== + +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +eslint-plugin-prettier@^5.2.3: + version "5.2.3" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.3.tgz#c4af01691a6fa9905207f0fbba0d7bea0902cce5" + integrity sha512-qJ+y0FfCp/mQYQ/vWQ3s7eUlFEL4PyKfAJxsnYTJ4YT73nsJBWqmEpFryxV9OeUiqmsTsYJ5Y+KDNaeP31wrRw== + dependencies: + prettier-linter-helpers "^1.0.0" + synckit "^0.9.1" + +eslint-plugin-unused-imports@^4.1.4: + version "4.1.4" + resolved "https://registry.yarnpkg.com/eslint-plugin-unused-imports/-/eslint-plugin-unused-imports-4.1.4.tgz#62ddc7446ccbf9aa7b6f1f0b00a980423cda2738" + integrity sha512-YptD6IzQjDardkl0POxnnRBhU1OEePMV0nd6siHaRBbd+lyh6NAhFEobiznKU7kTsSsDeSD62Pe7kAM1b7dAZQ== + +eslint-scope@^8.2.0: + version "8.2.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-8.2.0.tgz#377aa6f1cb5dc7592cfd0b7f892fd0cf352ce442" + integrity sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + +eslint-visitor-keys@^3.3.0: + version "3.4.3" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" + integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== + +eslint-visitor-keys@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz#687bacb2af884fcdda8a6e7d65c606f46a14cd45" + integrity sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw== + +eslint@^9.20.1: + version "9.20.1" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.20.1.tgz#923924c078f5226832449bac86662dd7e53c91d6" + integrity sha512-m1mM33o6dBUjxl2qb6wv6nGNwCAsns1eKtaQ4l/NPHeTvhiUPbtdfMyktxN4B3fgHIgsYh1VT3V9txblpQHq+g== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.12.1" + "@eslint/config-array" "^0.19.0" + "@eslint/core" "^0.11.0" + "@eslint/eslintrc" "^3.2.0" + "@eslint/js" "9.20.0" + "@eslint/plugin-kit" "^0.2.5" + "@humanfs/node" "^0.16.6" + "@humanwhocodes/module-importer" "^1.0.1" + "@humanwhocodes/retry" "^0.4.1" + "@types/estree" "^1.0.6" + "@types/json-schema" "^7.0.15" + ajv "^6.12.4" + chalk "^4.0.0" + cross-spawn "^7.0.6" + debug "^4.3.2" + escape-string-regexp "^4.0.0" + eslint-scope "^8.2.0" + eslint-visitor-keys "^4.2.0" + espree "^10.3.0" + esquery "^1.5.0" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^8.0.0" + find-up "^5.0.0" + glob-parent "^6.0.2" + ignore "^5.2.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + json-stable-stringify-without-jsonify "^1.0.1" + lodash.merge "^4.6.2" + minimatch "^3.1.2" + natural-compare "^1.4.0" + optionator "^0.9.3" + +espree@^10.0.1, espree@^10.3.0: + version "10.3.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-10.3.0.tgz#29267cf5b0cb98735b65e64ba07e0ed49d1eed8a" + integrity sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg== + dependencies: + acorn "^8.14.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^4.2.0" + +esprima@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== + +esquery@^1.5.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7" + integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^5.1.0, estraverse@^5.2.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +execa@^5.0.0: + version "5.1.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== + dependencies: + cross-spawn "^7.0.3" + get-stream "^6.0.0" + human-signals "^2.1.0" + is-stream "^2.0.0" + merge-stream "^2.0.0" + npm-run-path "^4.0.1" + onetime "^5.1.2" + signal-exit "^3.0.3" + strip-final-newline "^2.0.0" + +exit@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + integrity sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ== + +expect@^29.0.0, expect@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/expect/-/expect-29.7.0.tgz#578874590dcb3214514084c08115d8aee61e11bc" + integrity sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw== + dependencies: + "@jest/expect-utils" "^29.7.0" + jest-get-type "^29.6.3" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-diff@^1.1.2: + version "1.3.0" + resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.3.0.tgz#ece407fa550a64d638536cd727e129c61616e0f0" + integrity sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw== + +fast-glob@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" + integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + +fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== + +fastq@^1.6.0: + version "1.17.1" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.17.1.tgz#2a523f07a4e7b1e81a42b91b8bf2254107753b47" + integrity sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w== + dependencies: + reusify "^1.0.4" + +fb-watchman@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.2.tgz#e9524ee6b5c77e9e5001af0f85f3adbb8623255c" + integrity sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA== + dependencies: + bser "2.1.1" + +fflate@^0.8.2: + version "0.8.2" + resolved "https://registry.yarnpkg.com/fflate/-/fflate-0.8.2.tgz#fc8631f5347812ad6028bbe4a2308b2792aa1dea" + integrity sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A== + +file-entry-cache@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-8.0.0.tgz#7787bddcf1131bffb92636c69457bbc0edd6d81f" + integrity sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ== + dependencies: + flat-cache "^4.0.0" + +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== + dependencies: + to-regex-range "^5.0.1" + +find-up@^4.0.0, find-up@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== + dependencies: + locate-path "^5.0.0" + path-exists "^4.0.0" + +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +flat-cache@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-4.0.1.tgz#0ece39fcb14ee012f4b0410bd33dd9c1f011127c" + integrity sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw== + dependencies: + flatted "^3.2.9" + keyv "^4.5.4" + +flatted@^3.2.9: + version "3.3.2" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.2.tgz#adba1448a9841bec72b42c532ea23dbbedef1a27" + integrity sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA== + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +fsevents@^2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + +gensync@^1.0.0-beta.2: + version "1.0.0-beta.2" + resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" + integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg== + +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-package-type@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" + integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== + +get-stdin@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-8.0.0.tgz#cbad6a73feb75f6eeb22ba9e01f89aa28aa97a53" + integrity sha512-sY22aA6xchAzprjyqmSEQv4UbAAzRN0L2dQB0NlN5acTTK9Don6nhoc3eAbUnpZiCANAMfd/+40kVdKfFygohg== + +get-stream@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== + +glob-parent@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob-parent@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + +glob@^7.1.3, glob@^7.1.4: + version "7.2.3" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" + integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.1.1" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^8.0.1: + version "8.1.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-8.1.0.tgz#d388f656593ef708ee3e34640fdfb99a9fd1c33e" + integrity sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^5.0.1" + once "^1.3.0" + +globals@^11.1.0: + version "11.12.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== + +globals@^14.0.0: + version "14.0.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-14.0.0.tgz#898d7413c29babcf6bafe56fcadded858ada724e" + integrity sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ== + +graceful-fs@^4.2.9: + version "4.2.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" + integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== + +graphemer@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" + integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +hasown@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.0.tgz#f4c513d454a57b7c7e1650778de226b11700546c" + integrity sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA== + dependencies: + function-bind "^1.1.2" + +highlight.js@^10.7.1: + version "10.7.3" + resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.3.tgz#697272e3991356e40c3cac566a74eef681756531" + integrity sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A== + +html-escaper@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" + integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== + +human-signals@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== + +iconv-lite@^0.6.3: + version "0.6.3" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" + integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== + dependencies: + safer-buffer ">= 2.1.2 < 3.0.0" + +ignore-walk@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-5.0.1.tgz#5f199e23e1288f518d90358d461387788a154776" + integrity sha512-yemi4pMf51WKT7khInJqAvsIGzoqYXblnsz0ql8tM+yi1EKYTY1evX4NAbJrLL/Aanr2HyZeluqU+Oi7MGHokw== + dependencies: + minimatch "^5.0.1" + +ignore@^5.2.0, ignore@^5.3.1: + version "5.3.2" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" + integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== + +import-fresh@^3.2.1: + version "3.3.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +import-local@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.1.0.tgz#b4479df8a5fd44f6cdce24070675676063c95cb4" + integrity sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg== + dependencies: + pkg-dir "^4.2.0" + resolve-cwd "^3.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== + +indent-string@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" + integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@^2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg== + +is-core-module@^2.13.0: + version "2.13.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384" + integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw== + dependencies: + hasown "^2.0.0" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-generator-fn@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" + integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== + +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-stream@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" + integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz#2d166c4b0644d43a39f04bf6c2edd1e585f31756" + integrity sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg== + +istanbul-lib-instrument@^5.0.4: + version "5.2.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz#d10c8885c2125574e1c231cacadf955675e1ce3d" + integrity sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg== + dependencies: + "@babel/core" "^7.12.3" + "@babel/parser" "^7.14.7" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.2.0" + semver "^6.3.0" + +istanbul-lib-instrument@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.1.tgz#71e87707e8041428732518c6fb5211761753fbdf" + integrity sha512-EAMEJBsYuyyztxMxW3g7ugGPkrZsV57v0Hmv3mm1uQsmB+QnZuepg731CRaIgeUVSdmsTngOkSnauNF8p7FIhA== + dependencies: + "@babel/core" "^7.12.3" + "@babel/parser" "^7.14.7" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.2.0" + semver "^7.5.4" + +istanbul-lib-report@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz#908305bac9a5bd175ac6a74489eafd0fc2445a7d" + integrity sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw== + dependencies: + istanbul-lib-coverage "^3.0.0" + make-dir "^4.0.0" + supports-color "^7.1.0" + +istanbul-lib-source-maps@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz#895f3a709fcfba34c6de5a42939022f3e4358551" + integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw== + dependencies: + debug "^4.1.1" + istanbul-lib-coverage "^3.0.0" + source-map "^0.6.1" + +istanbul-reports@^3.1.3: + version "3.1.6" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.6.tgz#2544bcab4768154281a2f0870471902704ccaa1a" + integrity sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg== + dependencies: + html-escaper "^2.0.0" + istanbul-lib-report "^3.0.0" + +jest-changed-files@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-29.7.0.tgz#1c06d07e77c78e1585d020424dedc10d6e17ac3a" + integrity sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w== + dependencies: + execa "^5.0.0" + jest-util "^29.7.0" + p-limit "^3.1.0" + +jest-circus@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-29.7.0.tgz#b6817a45fcc835d8b16d5962d0c026473ee3668a" + integrity sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/expect" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + dedent "^1.0.0" + is-generator-fn "^2.0.0" + jest-each "^29.7.0" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-runtime "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" + p-limit "^3.1.0" + pretty-format "^29.7.0" + pure-rand "^6.0.0" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-cli@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-29.7.0.tgz#5592c940798e0cae677eec169264f2d839a37995" + integrity sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg== + dependencies: + "@jest/core" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" + chalk "^4.0.0" + create-jest "^29.7.0" + exit "^0.1.2" + import-local "^3.0.2" + jest-config "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" + yargs "^17.3.1" + +jest-config@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-29.7.0.tgz#bcbda8806dbcc01b1e316a46bb74085a84b0245f" + integrity sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ== + dependencies: + "@babel/core" "^7.11.6" + "@jest/test-sequencer" "^29.7.0" + "@jest/types" "^29.6.3" + babel-jest "^29.7.0" + chalk "^4.0.0" + ci-info "^3.2.0" + deepmerge "^4.2.2" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-circus "^29.7.0" + jest-environment-node "^29.7.0" + jest-get-type "^29.6.3" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-runner "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" + micromatch "^4.0.4" + parse-json "^5.2.0" + pretty-format "^29.7.0" + slash "^3.0.0" + strip-json-comments "^3.1.1" + +jest-diff@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.7.0.tgz#017934a66ebb7ecf6f205e84699be10afd70458a" + integrity sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw== + dependencies: + chalk "^4.0.0" + diff-sequences "^29.6.3" + jest-get-type "^29.6.3" + pretty-format "^29.7.0" + +jest-docblock@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-29.7.0.tgz#8fddb6adc3cdc955c93e2a87f61cfd350d5d119a" + integrity sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g== + dependencies: + detect-newline "^3.0.0" + +jest-each@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-29.7.0.tgz#162a9b3f2328bdd991beaabffbb74745e56577d1" + integrity sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ== + dependencies: + "@jest/types" "^29.6.3" + chalk "^4.0.0" + jest-get-type "^29.6.3" + jest-util "^29.7.0" + pretty-format "^29.7.0" + +jest-environment-node@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-29.7.0.tgz#0b93e111dda8ec120bc8300e6d1fb9576e164376" + integrity sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/fake-timers" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + jest-mock "^29.7.0" + jest-util "^29.7.0" + +jest-get-type@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.6.3.tgz#36f499fdcea197c1045a127319c0481723908fd1" + integrity sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw== + +jest-haste-map@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-29.7.0.tgz#3c2396524482f5a0506376e6c858c3bbcc17b104" + integrity sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA== + dependencies: + "@jest/types" "^29.6.3" + "@types/graceful-fs" "^4.1.3" + "@types/node" "*" + anymatch "^3.0.3" + fb-watchman "^2.0.0" + graceful-fs "^4.2.9" + jest-regex-util "^29.6.3" + jest-util "^29.7.0" + jest-worker "^29.7.0" + micromatch "^4.0.4" + walker "^1.0.8" + optionalDependencies: + fsevents "^2.3.2" + +jest-leak-detector@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz#5b7ec0dadfdfec0ca383dc9aa016d36b5ea4c728" + integrity sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw== + dependencies: + jest-get-type "^29.6.3" + pretty-format "^29.7.0" + +jest-matcher-utils@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz#ae8fec79ff249fd592ce80e3ee474e83a6c44f12" + integrity sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g== + dependencies: + chalk "^4.0.0" + jest-diff "^29.7.0" + jest-get-type "^29.6.3" + pretty-format "^29.7.0" + +jest-message-util@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.7.0.tgz#8bc392e204e95dfe7564abbe72a404e28e51f7f3" + integrity sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w== + dependencies: + "@babel/code-frame" "^7.12.13" + "@jest/types" "^29.6.3" + "@types/stack-utils" "^2.0.0" + chalk "^4.0.0" + graceful-fs "^4.2.9" + micromatch "^4.0.4" + pretty-format "^29.7.0" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-mock@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-29.7.0.tgz#4e836cf60e99c6fcfabe9f99d017f3fdd50a6347" + integrity sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw== + dependencies: + "@jest/types" "^29.6.3" + "@types/node" "*" + jest-util "^29.7.0" + +jest-pnp-resolver@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz#930b1546164d4ad5937d5540e711d4d38d4cad2e" + integrity sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w== + +jest-regex-util@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-29.6.3.tgz#4a556d9c776af68e1c5f48194f4d0327d24e8a52" + integrity sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg== + +jest-resolve-dependencies@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz#1b04f2c095f37fc776ff40803dc92921b1e88428" + integrity sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA== + dependencies: + jest-regex-util "^29.6.3" + jest-snapshot "^29.7.0" + +jest-resolve@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-29.7.0.tgz#64d6a8992dd26f635ab0c01e5eef4399c6bcbc30" + integrity sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA== + dependencies: + chalk "^4.0.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + jest-pnp-resolver "^1.2.2" + jest-util "^29.7.0" + jest-validate "^29.7.0" + resolve "^1.20.0" + resolve.exports "^2.0.0" + slash "^3.0.0" + +jest-runner@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-29.7.0.tgz#809af072d408a53dcfd2e849a4c976d3132f718e" + integrity sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ== + dependencies: + "@jest/console" "^29.7.0" + "@jest/environment" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + emittery "^0.13.1" + graceful-fs "^4.2.9" + jest-docblock "^29.7.0" + jest-environment-node "^29.7.0" + jest-haste-map "^29.7.0" + jest-leak-detector "^29.7.0" + jest-message-util "^29.7.0" + jest-resolve "^29.7.0" + jest-runtime "^29.7.0" + jest-util "^29.7.0" + jest-watcher "^29.7.0" + jest-worker "^29.7.0" + p-limit "^3.1.0" + source-map-support "0.5.13" + +jest-runtime@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-29.7.0.tgz#efecb3141cf7d3767a3a0cc8f7c9990587d3d817" + integrity sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/fake-timers" "^29.7.0" + "@jest/globals" "^29.7.0" + "@jest/source-map" "^29.6.3" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + cjs-module-lexer "^1.0.0" + collect-v8-coverage "^1.0.0" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + jest-message-util "^29.7.0" + jest-mock "^29.7.0" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" + slash "^3.0.0" + strip-bom "^4.0.0" + +jest-snapshot@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-29.7.0.tgz#c2c574c3f51865da1bb329036778a69bf88a6be5" + integrity sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw== + dependencies: + "@babel/core" "^7.11.6" + "@babel/generator" "^7.7.2" + "@babel/plugin-syntax-jsx" "^7.7.2" + "@babel/plugin-syntax-typescript" "^7.7.2" + "@babel/types" "^7.3.3" + "@jest/expect-utils" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + babel-preset-current-node-syntax "^1.0.0" + chalk "^4.0.0" + expect "^29.7.0" + graceful-fs "^4.2.9" + jest-diff "^29.7.0" + jest-get-type "^29.6.3" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + natural-compare "^1.4.0" + pretty-format "^29.7.0" + semver "^7.5.3" + +jest-util@^29.0.0, jest-util@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.7.0.tgz#23c2b62bfb22be82b44de98055802ff3710fc0bc" + integrity sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA== + dependencies: + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + ci-info "^3.2.0" + graceful-fs "^4.2.9" + picomatch "^2.2.3" + +jest-validate@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-29.7.0.tgz#7bf705511c64da591d46b15fce41400d52147d9c" + integrity sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw== + dependencies: + "@jest/types" "^29.6.3" + camelcase "^6.2.0" + chalk "^4.0.0" + jest-get-type "^29.6.3" + leven "^3.1.0" + pretty-format "^29.7.0" + +jest-watcher@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-29.7.0.tgz#7810d30d619c3a62093223ce6bb359ca1b28a2f2" + integrity sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g== + dependencies: + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + emittery "^0.13.1" + jest-util "^29.7.0" + string-length "^4.0.1" + +jest-worker@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-29.7.0.tgz#acad073acbbaeb7262bd5389e1bcf43e10058d4a" + integrity sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw== + dependencies: + "@types/node" "*" + jest-util "^29.7.0" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +jest@^29.4.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest/-/jest-29.7.0.tgz#994676fc24177f088f1c5e3737f5697204ff2613" + integrity sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw== + dependencies: + "@jest/core" "^29.7.0" + "@jest/types" "^29.6.3" + import-local "^3.0.2" + jest-cli "^29.7.0" + +js-tokens@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^3.13.1: + version "3.14.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" + integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== + dependencies: + argparse "^1.0.7" + esprima "^4.0.0" + +js-yaml@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +jsesc@^2.5.1: + version "2.5.2" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== + +json-buffer@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== + +json-parse-even-better-errors@^2.3.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== + +json5@^2.2.2, json5@^2.2.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" + integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== + +jsonc-parser@^3.2.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.2.1.tgz#031904571ccf929d7670ee8c547545081cb37f1a" + integrity sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA== + +keyv@^4.5.4: + version "4.5.4" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" + integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== + dependencies: + json-buffer "3.0.1" + +kleur@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" + integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== + +leven@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" + integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== + +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + +lines-and-columns@^1.1.6: + version "1.2.4" + resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632" + integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg== + +locate-path@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== + dependencies: + p-locate "^4.1.0" + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + +lodash.memoize@4.x: + version "4.1.2" + resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" + integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag== + +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +lru-cache@^10.4.3: + version "10.4.3" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.4.3.tgz#410fc8a17b70e598013df257c2446b7f3383f119" + integrity sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ== + +lru-cache@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== + dependencies: + yallist "^3.0.2" + +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + +make-dir@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-4.0.0.tgz#c3c2307a771277cd9638305f915c29ae741b614e" + integrity sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw== + dependencies: + semver "^7.5.3" + +make-error@1.x, make-error@^1.1.1: + version "1.3.6" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" + integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== + +makeerror@1.0.12: + version "1.0.12" + resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a" + integrity sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg== + dependencies: + tmpl "1.0.5" + +marked-terminal@^7.1.0: + version "7.2.1" + resolved "https://registry.yarnpkg.com/marked-terminal/-/marked-terminal-7.2.1.tgz#9c1ae073a245a03c6a13e3eeac6f586f29856068" + integrity sha512-rQ1MoMFXZICWNsKMiiHwP/Z+92PLKskTPXj+e7uwXmuMPkNn7iTqC+IvDekVm1MPeC9wYQeLxeFaOvudRR/XbQ== + dependencies: + ansi-escapes "^7.0.0" + ansi-regex "^6.1.0" + chalk "^5.3.0" + cli-highlight "^2.1.11" + cli-table3 "^0.6.5" + node-emoji "^2.1.3" + supports-hyperlinks "^3.1.0" + +marked@^9.1.2: + version "9.1.6" + resolved "https://registry.yarnpkg.com/marked/-/marked-9.1.6.tgz#5d2a3f8180abfbc5d62e3258a38a1c19c0381695" + integrity sha512-jcByLnIFkd5gSXZmjNvS1TlmRhCXZjIzHYlaGkPlLIekG55JDR2Z4va9tZwCiP+/RDERiNhMOFu01xd6O5ct1Q== + +merge-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== + +merge2@^1.3.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +micromatch@^4.0.4: + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== + dependencies: + braces "^3.0.3" + picomatch "^2.3.1" + +mimic-fn@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== + +minimatch@^3.0.4, minimatch@^3.1.1, minimatch@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimatch@^5.0.1: + version "5.1.6" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" + integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== + dependencies: + brace-expansion "^2.0.1" + +minimatch@^9.0.4: + version "9.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== + dependencies: + brace-expansion "^2.0.1" + +minimist@^1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" + integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== + +mri@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/mri/-/mri-1.2.0.tgz#6721480fec2a11a4889861115a48b6cbe7cc8f0b" + integrity sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA== + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +ms@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +mz@^2.4.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" + integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q== + dependencies: + any-promise "^1.0.0" + object-assign "^4.0.1" + thenify-all "^1.0.0" + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== + +node-emoji@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/node-emoji/-/node-emoji-2.1.3.tgz#93cfabb5cc7c3653aa52f29d6ffb7927d8047c06" + integrity sha512-E2WEOVsgs7O16zsURJ/eH8BqhF029wGpEOnv7Urwdo2wmQanOACwJQh0devF9D9RhoZru0+9JXIS0dBXIAz+lA== + dependencies: + "@sindresorhus/is" "^4.6.0" + char-regex "^1.0.2" + emojilib "^2.4.0" + skin-tone "^2.0.0" + +node-int64@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== + +node-releases@^2.0.14: + version "2.0.14" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b" + integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw== + +normalize-path@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +npm-bundled@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-2.0.1.tgz#94113f7eb342cd7a67de1e789f896b04d2c600f4" + integrity sha512-gZLxXdjEzE/+mOstGDqR6b0EkhJ+kM6fxM6vUuckuctuVPh80Q6pw/rSZj9s4Gex9GxWtIicO1pc8DB9KZWudw== + dependencies: + npm-normalize-package-bin "^2.0.0" + +npm-normalize-package-bin@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/npm-normalize-package-bin/-/npm-normalize-package-bin-2.0.0.tgz#9447a1adaaf89d8ad0abe24c6c84ad614a675fff" + integrity sha512-awzfKUO7v0FscrSpRoogyNm0sajikhBWpU0QMrW09AMi9n1PoKU6WaIqUzuJSQnpciZZmJ/jMZ2Egfmb/9LiWQ== + +npm-packlist@^5.1.3: + version "5.1.3" + resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-5.1.3.tgz#69d253e6fd664b9058b85005905012e00e69274b" + integrity sha512-263/0NGrn32YFYi4J533qzrQ/krmmrWwhKkzwTuM4f/07ug51odoaNjUexxO4vxlzURHcmYMH1QjvHjsNDKLVg== + dependencies: + glob "^8.0.1" + ignore-walk "^5.0.1" + npm-bundled "^2.0.0" + npm-normalize-package-bin "^2.0.0" + +npm-run-path@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== + dependencies: + path-key "^3.0.0" + +object-assign@^4.0.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +onetime@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== + dependencies: + mimic-fn "^2.1.0" + +optionator@^0.9.3: + version "0.9.3" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.3.tgz#007397d44ed1872fdc6ed31360190f81814e2c64" + integrity sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg== + dependencies: + "@aashutoshrathi/word-wrap" "^1.2.3" + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + +p-all@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-all/-/p-all-3.0.0.tgz#077c023c37e75e760193badab2bad3ccd5782bfb" + integrity sha512-qUZbvbBFVXm6uJ7U/WDiO0fv6waBMbjlCm4E66oZdRR+egswICarIdHyVSZZHudH8T5SF8x/JG0q0duFzPnlBw== + dependencies: + p-map "^4.0.0" + +p-limit@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== + dependencies: + p-try "^2.0.0" + +p-limit@^3.0.2, p-limit@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== + dependencies: + p-limit "^2.2.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + +p-map@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" + integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== + dependencies: + aggregate-error "^3.0.0" + +p-try@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== + +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + +parse-json@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd" + integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg== + dependencies: + "@babel/code-frame" "^7.0.0" + error-ex "^1.3.1" + json-parse-even-better-errors "^2.3.0" + lines-and-columns "^1.1.6" + +parse5-htmlparser2-tree-adapter@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz#2cdf9ad823321140370d4dbf5d3e92c7c8ddc6e6" + integrity sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA== + dependencies: + parse5 "^6.0.1" + +parse5@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.1.tgz#f68e4e5ba1852ac2cadc00f4555fff6c2abb6178" + integrity sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug== + +parse5@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" + integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +path-key@^3.0.0, path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +picocolors@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" + integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== + +picocolors@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" + integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== + +picomatch@^2.0.4, picomatch@^2.2.3, picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +pirates@^4.0.4: + version "4.0.6" + resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.6.tgz#3018ae32ecfcff6c29ba2267cbf21166ac1f36b9" + integrity sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg== + +pkg-dir@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== + dependencies: + find-up "^4.0.0" + +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + +prettier-linter-helpers@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz#d23d41fe1375646de2d0104d3454a3008802cf7b" + integrity sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w== + dependencies: + fast-diff "^1.1.2" + +prettier@^3.0.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.1.1.tgz#6ba9f23165d690b6cbdaa88cb0807278f7019848" + integrity sha512-22UbSzg8luF4UuZtzgiUOfcGM8s4tjBv6dJRT7j275NXsy2jb4aJa4NNveul5x4eqlF1wuhuR2RElK71RvmVaw== + +pretty-format@^29.0.0, pretty-format@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.7.0.tgz#ca42c758310f365bfa71a0bda0a807160b776812" + integrity sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ== + dependencies: + "@jest/schemas" "^29.6.3" + ansi-styles "^5.0.0" + react-is "^18.0.0" + +prompts@^2.0.1: + version "2.4.2" + resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" + integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== + dependencies: + kleur "^3.0.3" + sisteransi "^1.0.5" + +publint@^0.2.12: + version "0.2.12" + resolved "https://registry.yarnpkg.com/publint/-/publint-0.2.12.tgz#d25cd6bd243d5bdd640344ecdddb3eeafdcc4059" + integrity sha512-YNeUtCVeM4j9nDiTT2OPczmlyzOkIXNtdDZnSuajAxS/nZ6j3t7Vs9SUB4euQNddiltIwu7Tdd3s+hr08fAsMw== + dependencies: + npm-packlist "^5.1.3" + picocolors "^1.1.1" + sade "^1.8.1" + +punycode@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.0.tgz#f67fa67c94da8f4d0cfff981aee4118064199b8f" + integrity sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA== + +pure-rand@^6.0.0: + version "6.0.4" + resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-6.0.4.tgz#50b737f6a925468679bff00ad20eade53f37d5c7" + integrity sha512-LA0Y9kxMYv47GIPJy6MI84fqTd2HmYZI83W/kM/SkKfDlajnZYfmXFTxkbY+xSBPkLJxltMa9hIkmdc29eguMA== + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + +react-is@^18.0.0: + version "18.2.0" + resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" + integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== + +readable-stream@^3.4.0: + version "3.6.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.2.tgz#56a9b36ea965c00c5a93ef31eb111a0f11056967" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + +resolve-cwd@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" + integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== + dependencies: + resolve-from "^5.0.0" + +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +resolve-from@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== + +resolve.exports@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-2.0.2.tgz#f8c934b8e6a13f539e38b7098e2e36134f01e800" + integrity sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg== + +resolve@^1.20.0: + version "1.22.8" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" + integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== + dependencies: + is-core-module "^2.13.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +sade@^1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/sade/-/sade-1.8.1.tgz#0a78e81d658d394887be57d2a409bf703a3b2701" + integrity sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A== + dependencies: + mri "^1.1.0" + +safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +"safer-buffer@>= 2.1.2 < 3.0.0": + version "2.1.2" + resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== + +semver@^6.3.0, semver@^6.3.1: + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + +semver@^7.5.3: + version "7.5.4" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e" + integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA== + dependencies: + lru-cache "^6.0.0" + +semver@^7.5.4: + version "7.6.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.3.tgz#980f7b5550bc175fb4dc09403085627f9eb33143" + integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== + +semver@^7.6.0: + version "7.7.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.1.tgz#abd5098d82b18c6c81f6074ff2647fd3e7220c9f" + integrity sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA== + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +signal-exit@^3.0.3, signal-exit@^3.0.7: + version "3.0.7" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" + integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== + +sisteransi@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" + integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== + +skin-tone@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/skin-tone/-/skin-tone-2.0.0.tgz#4e3933ab45c0d4f4f781745d64b9f4c208e41237" + integrity sha512-kUMbT1oBJCpgrnKoSr0o6wPtvRWT9W9UKvGLwfJYO2WuahZRHOpEyL1ckyMGgMWh0UdpmaoFqKKD29WTomNEGA== + dependencies: + unicode-emoji-modifier-base "^1.0.0" + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + +source-map-support@0.5.13: + version "0.5.13" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932" + integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@^0.6.0, source-map@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + integrity sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g== + +stack-utils@^2.0.3: + version "2.0.6" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.6.tgz#aaf0748169c02fc33c8232abccf933f54a1cc34f" + integrity sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ== + dependencies: + escape-string-regexp "^2.0.0" + +string-length@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" + integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ== + dependencies: + char-regex "^1.0.2" + strip-ansi "^6.0.0" + +string-to-stream@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/string-to-stream/-/string-to-stream-3.0.1.tgz#480e6fb4d5476d31cb2221f75307a5dcb6638a42" + integrity sha512-Hl092MV3USJuUCC6mfl9sPzGloA3K5VwdIeJjYIkXY/8K+mUvaeEabWJgArp+xXrsWxCajeT2pc4axbVhIZJyg== + dependencies: + readable-stream "^3.4.0" + +string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== + +strip-bom@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" + integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== + +strip-final-newline@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== + +strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +superstruct@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/superstruct/-/superstruct-1.0.4.tgz#0adb99a7578bd2f1c526220da6571b2d485d91ca" + integrity sha512-7JpaAoX2NGyoFlI9NBh66BQXGONc+uE+MRS5i2iOBKuS4e+ccgMDjATgZldkah+33DakBxDHiss9kvUcGAO8UQ== + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== + dependencies: + has-flag "^3.0.0" + +supports-color@^7.0.0, supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-color@^8.0.0: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +supports-hyperlinks@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-3.1.0.tgz#b56150ff0173baacc15f21956450b61f2b18d3ac" + integrity sha512-2rn0BZ+/f7puLOHZm1HOJfwBggfaHXUpPUSSG/SWM4TWp5KCfmNYwnC3hruy2rZlMnmWZ+QAGpZfchu3f3695A== + dependencies: + has-flag "^4.0.0" + supports-color "^7.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +synckit@0.8.8, synckit@^0.9.1: + version "0.8.8" + resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.8.8.tgz#fe7fe446518e3d3d49f5e429f443cf08b6edfcd7" + integrity sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ== + dependencies: + "@pkgr/core" "^0.1.0" + tslib "^2.6.2" + +test-exclude@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" + integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== + dependencies: + "@istanbuljs/schema" "^0.1.2" + glob "^7.1.4" + minimatch "^3.0.4" + +thenify-all@^1.0.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" + integrity sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA== + dependencies: + thenify ">= 3.1.0 < 4" + +"thenify@>= 3.1.0 < 4": + version "3.3.1" + resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.1.tgz#8932e686a4066038a016dd9e2ca46add9838a95f" + integrity sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw== + dependencies: + any-promise "^1.0.0" + +tmpl@1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.5.tgz#8683e0b902bb9c20c4f726e3c0b69f36518c07cc" + integrity sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw== + +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +ts-api-utils@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-2.0.1.tgz#660729385b625b939aaa58054f45c058f33f10cd" + integrity sha512-dnlgjFSVetynI8nzgJ+qF62efpglpWRk8isUEWZGWlJYySCTD6aKvbUDu+zbPeDakk3bg5H4XpitHukgfL1m9w== + +ts-jest@^29.1.0: + version "29.1.1" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-29.1.1.tgz#f58fe62c63caf7bfcc5cc6472082f79180f0815b" + integrity sha512-D6xjnnbP17cC85nliwGiL+tpoKN0StpgE0TeOjXQTU6MVCfsB4v7aW05CgQ/1OywGb0x/oy9hHFnN+sczTiRaA== + dependencies: + bs-logger "0.x" + fast-json-stable-stringify "2.x" + jest-util "^29.0.0" + json5 "^2.2.3" + lodash.memoize "4.x" + make-error "1.x" + semver "^7.5.3" + yargs-parser "^21.0.1" + +ts-node@^10.5.0: + version "10.7.0" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.7.0.tgz#35d503d0fab3e2baa672a0e94f4b40653c2463f5" + integrity sha512-TbIGS4xgJoX2i3do417KSaep1uRAW/Lu+WAL2doDHC0D6ummjirVOXU5/7aiZotbQ5p1Zp9tP7U6cYhA0O7M8A== + dependencies: + "@cspotcode/source-map-support" "0.7.0" + "@tsconfig/node10" "^1.0.7" + "@tsconfig/node12" "^1.0.7" + "@tsconfig/node14" "^1.0.0" + "@tsconfig/node16" "^1.0.2" + acorn "^8.4.1" + acorn-walk "^8.1.1" + arg "^4.1.0" + create-require "^1.1.0" + diff "^4.0.1" + make-error "^1.1.1" + v8-compile-cache-lib "^3.0.0" + yn "3.1.1" + +"tsc-multi@https://github.com/stainless-api/tsc-multi/releases/download/v1.1.4/tsc-multi-1.1.4.tgz": + version "1.1.4" + resolved "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.4/tsc-multi-1.1.4.tgz#cbed459a9e902f5295ec3daaf1c7aa3b10427e55" + dependencies: + debug "^4.3.7" + fast-glob "^3.3.2" + get-stdin "^8.0.0" + p-all "^3.0.0" + picocolors "^1.1.1" + signal-exit "^3.0.7" + string-to-stream "^3.0.1" + superstruct "^1.0.4" + tslib "^2.8.1" + yargs "^17.7.2" + +tsconfig-paths@^4.0.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz#ef78e19039133446d244beac0fd6a1632e2d107c" + integrity sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg== + dependencies: + json5 "^2.2.2" + minimist "^1.2.6" + strip-bom "^3.0.0" + +tslib@^2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" + integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== + +tslib@^2.8.1: + version "2.8.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" + integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== + +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + +type-detect@4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== + +type-fest@^0.21.3: + version "0.21.3" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.21.3.tgz#d260a24b0198436e133fa26a524a6d65fa3b2e37" + integrity sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w== + +typescript-eslint@8.31.1: + version "8.31.1" + resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-8.31.1.tgz#b77ab1e48ced2daab9225ff94bab54391a4af69b" + integrity sha512-j6DsEotD/fH39qKzXTQRwYYWlt7D+0HmfpOK+DVhwJOFLcdmn92hq3mBb7HlKJHbjjI/gTOqEcc9d6JfpFf/VA== + dependencies: + "@typescript-eslint/eslint-plugin" "8.31.1" + "@typescript-eslint/parser" "8.31.1" + "@typescript-eslint/utils" "8.31.1" + +typescript@5.6.1-rc: + version "5.6.1-rc" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.6.1-rc.tgz#d5e4d7d8170174fed607b74cc32aba3d77018e02" + integrity sha512-E3b2+1zEFu84jB0YQi9BORDjz9+jGbwwy1Zi3G0LUNw7a7cePUrHMRNy8aPh53nXpkFGVHSxIZo5vKTfYaFiBQ== + +typescript@5.8.3: + version "5.8.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.8.3.tgz#92f8a3e5e3cf497356f4178c34cd65a7f5e8440e" + integrity sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ== + +undici-types@~5.26.4: + version "5.26.5" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" + integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== + +undici-types@~6.19.2: + version "6.19.8" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" + integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== + +unicode-emoji-modifier-base@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unicode-emoji-modifier-base/-/unicode-emoji-modifier-base-1.0.0.tgz#dbbd5b54ba30f287e2a8d5a249da6c0cef369459" + integrity sha512-yLSH4py7oFH3oG/9K+XWrz1pSi3dfUrWEnInbxMfArOfc1+33BlGPQtLsOYwvdMy11AwUBetYuaRxSPqgkq+8g== + +update-browserslist-db@^1.0.13: + version "1.0.13" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz#3c5e4f5c083661bd38ef64b6328c26ed6c8248c4" + integrity sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg== + dependencies: + escalade "^3.1.1" + picocolors "^1.0.0" + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +util-deprecate@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + +v8-compile-cache-lib@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.0.tgz#0582bcb1c74f3a2ee46487ceecf372e46bce53e8" + integrity sha512-mpSYqfsFvASnSn5qMiwrr4VKfumbPyONLCOPmsR3A6pTY/r0+tSaVbgPWSAIuzbk3lCTa+FForeTiO+wBQGkjA== + +v8-to-istanbul@^9.0.1: + version "9.2.0" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz#2ed7644a245cddd83d4e087b9b33b3e62dfd10ad" + integrity sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA== + dependencies: + "@jridgewell/trace-mapping" "^0.3.12" + "@types/istanbul-lib-coverage" "^2.0.1" + convert-source-map "^2.0.0" + +validate-npm-package-name@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/validate-npm-package-name/-/validate-npm-package-name-5.0.1.tgz#a316573e9b49f3ccd90dbb6eb52b3f06c6d604e8" + integrity sha512-OljLrQ9SQdOUqTaQxqL5dEfZWrXExyyWsozYlAWFawPVNuD83igl7uJD2RTkNMbniIYgt8l81eCJGIdQF7avLQ== + +walker@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" + integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== + dependencies: + makeerror "1.0.12" + +which@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +write-file-atomic@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-4.0.2.tgz#a9df01ae5b77858a027fd2e80768ee433555fcfd" + integrity sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg== + dependencies: + imurmurhash "^0.1.4" + signal-exit "^3.0.7" + +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yallist@^3.0.2: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== + +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== + +yargs-parser@^20.2.2: + version "20.2.9" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" + integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== + +yargs-parser@^21.0.1, yargs-parser@^21.1.1: + version "21.1.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" + integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw== + +yargs@^16.0.0: + version "16.2.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" + integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.0" + y18n "^5.0.5" + yargs-parser "^20.2.2" + +yargs@^17.3.1, yargs@^17.7.2: + version "17.7.2" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" + integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== + dependencies: + cliui "^8.0.1" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.3" + y18n "^5.0.5" + yargs-parser "^21.1.1" + +yn@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" + integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q== + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==