diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
index 763462f..43fd5a7 100644
--- a/.devcontainer/devcontainer.json
+++ b/.devcontainer/devcontainer.json
@@ -9,9 +9,7 @@
"postCreateCommand": "yarn install",
"customizations": {
"vscode": {
- "extensions": [
- "esbenp.prettier-vscode"
- ]
+ "extensions": ["esbenp.prettier-vscode"]
}
}
}
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index e3530dc..8c21a27 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -1,19 +1,18 @@
name: CI
on:
push:
- branches:
- - main
- pull_request:
- branches:
- - main
- - next
+ branches-ignore:
+ - 'generated'
+ - 'codegen/**'
+ - 'integrated/**'
+ - 'stl-preview-head/**'
+ - 'stl-preview-base/**'
jobs:
lint:
+ timeout-minutes: 10
name: lint
- runs-on: ubuntu-latest
-
-
+ runs-on: ${{ github.repository == 'stainless-sdks/gitpod-typescript' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }}
steps:
- uses: actions/checkout@v4
@@ -29,10 +28,12 @@ jobs:
run: ./scripts/lint
build:
+ timeout-minutes: 5
name: build
- runs-on: ubuntu-latest
-
-
+ 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
@@ -46,10 +47,25 @@ jobs:
- 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: ubuntu-latest
-
+ runs-on: ${{ github.repository == 'stainless-sdks/gitpod-typescript' && 'depot-ubuntu-24.04' || 'ubuntu-latest' }}
steps:
- uses: actions/checkout@v4
@@ -63,4 +79,3 @@ jobs:
- name: Run tests
run: ./scripts/test
-
diff --git a/.github/workflows/release-doctor.yml b/.github/workflows/release-doctor.yml
index 742b303..f875bac 100644
--- a/.github/workflows/release-doctor.yml
+++ b/.github/workflows/release-doctor.yml
@@ -19,4 +19,3 @@ jobs:
bash ./bin/check-release-environment
env:
NPM_TOKEN: ${{ secrets.GITPOD_NPM_TOKEN || secrets.NPM_TOKEN }}
-
diff --git a/.release-please-manifest.json b/.release-please-manifest.json
index f1c1e58..bcd0522 100644
--- a/.release-please-manifest.json
+++ b/.release-please-manifest.json
@@ -1,3 +1,3 @@
{
- ".": "0.5.0"
+ ".": "0.6.0"
}
diff --git a/.stats.yml b/.stats.yml
index 2c4d8ac..9cdc117 100644
--- a/.stats.yml
+++ b/.stats.yml
@@ -1,2 +1,4 @@
-configured_endpoints: 111
-openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/gitpod%2Fgitpod-3655d5ad0ac3e228c1519af70dbf3d0bfa3c47a2d06d4cac92a650da051b49a6.yml
+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/CHANGELOG.md b/CHANGELOG.md
index b82eb11..b76115e 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,66 @@
# Changelog
+## 0.6.0 (2025-05-09)
+
+Full Changelog: [v0.5.0...v0.6.0](https://github.com/gitpod-io/gitpod-sdk-typescript/compare/v0.5.0...v0.6.0)
+
+### Features
+
+* **api:** manual updates ([77b6f44](https://github.com/gitpod-io/gitpod-sdk-typescript/commit/77b6f44b695808f66ce955683f86965c3b8605fb))
+* **api:** manual updates ([f0edc96](https://github.com/gitpod-io/gitpod-sdk-typescript/commit/f0edc9696d24e0a4e4ed648b585883616cde251f))
+* **api:** manual updates ([f50f5ad](https://github.com/gitpod-io/gitpod-sdk-typescript/commit/f50f5adf1ea13bb39845ff8644e2f670bc01856d))
+
+
+### Bug Fixes
+
+* **api:** improve type resolution when importing as a package ([#66](https://github.com/gitpod-io/gitpod-sdk-typescript/issues/66)) ([8aa007b](https://github.com/gitpod-io/gitpod-sdk-typescript/commit/8aa007bc39d87e8b96861748a23d4faa5d084c8a))
+* **client:** fix TypeError with undefined File ([#50](https://github.com/gitpod-io/gitpod-sdk-typescript/issues/50)) ([1262a7b](https://github.com/gitpod-io/gitpod-sdk-typescript/commit/1262a7bcd5e0619e1eaef399ee967b629c79ce09))
+* **client:** send `X-Stainless-Timeout` in seconds ([#63](https://github.com/gitpod-io/gitpod-sdk-typescript/issues/63)) ([dab2433](https://github.com/gitpod-io/gitpod-sdk-typescript/commit/dab243394f6b0f60cedc65f3eabcf1bfe64ed640))
+* **client:** send all configured auth headers ([#68](https://github.com/gitpod-io/gitpod-sdk-typescript/issues/68)) ([3ced793](https://github.com/gitpod-io/gitpod-sdk-typescript/commit/3ced7939c98da7bc8c42a457da3aee4510a778a7))
+* **exports:** ensure resource imports don't require /index ([#57](https://github.com/gitpod-io/gitpod-sdk-typescript/issues/57)) ([23166e6](https://github.com/gitpod-io/gitpod-sdk-typescript/commit/23166e607ec2b8915a97e974e09cdc0abdbc6c23))
+* **internal:** add mts file + crypto shim types ([#58](https://github.com/gitpod-io/gitpod-sdk-typescript/issues/58)) ([716b94c](https://github.com/gitpod-io/gitpod-sdk-typescript/commit/716b94c4be5a42cfaf9f59fcdb9332b912113869))
+* **internal:** clean up undefined File test ([#51](https://github.com/gitpod-io/gitpod-sdk-typescript/issues/51)) ([e1e0fb5](https://github.com/gitpod-io/gitpod-sdk-typescript/commit/e1e0fb509bfd526c9a8183480ad88330f0c7b240))
+* **internal:** fix file uploads in node 18 jest ([702757c](https://github.com/gitpod-io/gitpod-sdk-typescript/commit/702757cc250c54fa31731233f3b88841b42baa32))
+* **internal:** return in castToError instead of throwing ([#43](https://github.com/gitpod-io/gitpod-sdk-typescript/issues/43)) ([2f70ad9](https://github.com/gitpod-io/gitpod-sdk-typescript/commit/2f70ad9e95854605f9f38c401d49f8422d62af75))
+* **mcp:** remove unused tools.ts ([#67](https://github.com/gitpod-io/gitpod-sdk-typescript/issues/67)) ([65686bf](https://github.com/gitpod-io/gitpod-sdk-typescript/commit/65686bf96f2a2147c620810605bc66876ec0c13e))
+* **tests:** manually reset node:buffer File ([#52](https://github.com/gitpod-io/gitpod-sdk-typescript/issues/52)) ([2eded46](https://github.com/gitpod-io/gitpod-sdk-typescript/commit/2eded46344af89fbaef371ab685056b8952aa946))
+
+
+### Chores
+
+* **ci:** add timeout thresholds for CI jobs ([d78258c](https://github.com/gitpod-io/gitpod-sdk-typescript/commit/d78258ce7b00f01f7714c59bda0d12d3f70b7ec3))
+* **ci:** only use depot for staging repos ([678516c](https://github.com/gitpod-io/gitpod-sdk-typescript/commit/678516c59e2a0a39caa817aa847f9a3f197172b7))
+* **client:** make jsonl methods consistent with other streaming methods ([#65](https://github.com/gitpod-io/gitpod-sdk-typescript/issues/65)) ([62c4790](https://github.com/gitpod-io/gitpod-sdk-typescript/commit/62c4790ed0515d7644fca6075b5d9304bd4b1642))
+* **client:** minor internal fixes ([e3c6fb8](https://github.com/gitpod-io/gitpod-sdk-typescript/commit/e3c6fb879bc94b55e66f65a5238102ba390387a8))
+* **client:** move misc public files to new `core/` directory, deprecate old paths ([#62](https://github.com/gitpod-io/gitpod-sdk-typescript/issues/62)) ([e4008c3](https://github.com/gitpod-io/gitpod-sdk-typescript/commit/e4008c3ab36557410e2124287eb9ab861e5d81d2))
+* **client:** only accept standard types for file uploads ([#47](https://github.com/gitpod-io/gitpod-sdk-typescript/issues/47)) ([cd888bc](https://github.com/gitpod-io/gitpod-sdk-typescript/commit/cd888bc3c16d0d2cbf3b3c96ab23dc7d46360598))
+* **docs:** improve docs for withResponse/asResponse ([#54](https://github.com/gitpod-io/gitpod-sdk-typescript/issues/54)) ([25092c5](https://github.com/gitpod-io/gitpod-sdk-typescript/commit/25092c5070acc3602094bf34f304105cb7bd7157))
+* **exports:** cleaner resource index imports ([#60](https://github.com/gitpod-io/gitpod-sdk-typescript/issues/60)) ([0049aac](https://github.com/gitpod-io/gitpod-sdk-typescript/commit/0049aac07585fb4a1536ef6ff191b4ba5d5b9720))
+* **exports:** stop using path fallbacks ([#61](https://github.com/gitpod-io/gitpod-sdk-typescript/issues/61)) ([a9df2c1](https://github.com/gitpod-io/gitpod-sdk-typescript/commit/a9df2c166e44d19ff8b374e5225d29971c72bb3e))
+* **internal:** add aliases for Record and Array ([#64](https://github.com/gitpod-io/gitpod-sdk-typescript/issues/64)) ([38e00c9](https://github.com/gitpod-io/gitpod-sdk-typescript/commit/38e00c9995d8528c361bf709d3951a0f00238ada))
+* **internal:** codegen related update ([e94c558](https://github.com/gitpod-io/gitpod-sdk-typescript/commit/e94c55895af8caf60720420c33c1e22c6e2d5bd4))
+* **internal:** codegen related update ([c60c38f](https://github.com/gitpod-io/gitpod-sdk-typescript/commit/c60c38f7f805d86e56d6a2f96c742b1549d62e5c))
+* **internal:** codegen related update ([#55](https://github.com/gitpod-io/gitpod-sdk-typescript/issues/55)) ([71a1bef](https://github.com/gitpod-io/gitpod-sdk-typescript/commit/71a1bef58884eb34434a3e590cf0942c8166d33b))
+* **internal:** constrain synckit dev dependency ([#49](https://github.com/gitpod-io/gitpod-sdk-typescript/issues/49)) ([41da630](https://github.com/gitpod-io/gitpod-sdk-typescript/commit/41da630123709c225f8c173bbd2aace382d0e865))
+* **internal:** fix tests failing on node v18 ([#48](https://github.com/gitpod-io/gitpod-sdk-typescript/issues/48)) ([c1031bd](https://github.com/gitpod-io/gitpod-sdk-typescript/commit/c1031bd67090cc27d55472a5a32ee70df9ee781e))
+* **internal:** improve node 18 shims ([726127a](https://github.com/gitpod-io/gitpod-sdk-typescript/commit/726127ae7ad639fc5587724e20559893ea3c67eb))
+* **internal:** minor client file refactoring ([#59](https://github.com/gitpod-io/gitpod-sdk-typescript/issues/59)) ([51d47fd](https://github.com/gitpod-io/gitpod-sdk-typescript/commit/51d47fd93e6be04336019ec05c60841a5d25195c))
+* **internal:** reduce CI branch coverage ([e8cd029](https://github.com/gitpod-io/gitpod-sdk-typescript/commit/e8cd029655896872fa1ccd8b71807f8c0ac565c9))
+* **internal:** refactor utils ([eafa310](https://github.com/gitpod-io/gitpod-sdk-typescript/commit/eafa310bb3964addb8bbbf8c8811564f6985068e))
+* **internal:** remove extra empty newlines ([#56](https://github.com/gitpod-io/gitpod-sdk-typescript/issues/56)) ([6431dc9](https://github.com/gitpod-io/gitpod-sdk-typescript/commit/6431dc9927a315b9faf1e906c95930bcec65f3d5))
+* **internal:** remove unnecessary todo ([#45](https://github.com/gitpod-io/gitpod-sdk-typescript/issues/45)) ([bd9e536](https://github.com/gitpod-io/gitpod-sdk-typescript/commit/bd9e5361115c7f9adc8c8d9798f38a04b55ab03c))
+* **internal:** share typescript helpers ([b52aa07](https://github.com/gitpod-io/gitpod-sdk-typescript/commit/b52aa0747ab51dbdf0eeb63e3fce2c255f47a06c))
+* **internal:** upload builds and expand CI branch coverage ([dbd4446](https://github.com/gitpod-io/gitpod-sdk-typescript/commit/dbd4446148041e01ec058c0a19568a17ad7384f7))
+* **perf:** faster base64 decoding ([b3a1e96](https://github.com/gitpod-io/gitpod-sdk-typescript/commit/b3a1e96efe94fd726a49c050eb1a6e0069171983))
+* **tests:** improve enum examples ([#69](https://github.com/gitpod-io/gitpod-sdk-typescript/issues/69)) ([af4a60a](https://github.com/gitpod-io/gitpod-sdk-typescript/commit/af4a60aa5f1bc957cdb96b0996f4ee02c0d7d469))
+* **types:** improved go to definition on fetchOptions ([#53](https://github.com/gitpod-io/gitpod-sdk-typescript/issues/53)) ([54a7db8](https://github.com/gitpod-io/gitpod-sdk-typescript/commit/54a7db864f182bd872aeceae04747930a3e419a7))
+
+
+### Documentation
+
+* **readme:** fix typo ([fea4ecb](https://github.com/gitpod-io/gitpod-sdk-typescript/commit/fea4ecb31efa7b73aec94c3aed1f574b80611110))
+* update URLs from stainlessapi.com to stainless.com ([#46](https://github.com/gitpod-io/gitpod-sdk-typescript/issues/46)) ([6450e47](https://github.com/gitpod-io/gitpod-sdk-typescript/commit/6450e47a5f12103274528a67028b91a01b9c55b8))
+
## 0.5.0 (2025-02-21)
Full Changelog: [v0.4.0...v0.5.0](https://github.com/gitpod-io/gitpod-sdk-typescript/compare/v0.4.0...v0.5.0)
diff --git a/README.md b/README.md
index e071c46..a2f50c6 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,7 @@ This library provides convenient access to the Gitpod REST API from server-side
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.stainlessapi.com/).
+It is generated with [Stainless](https://www.stainless.com/).
## Installation
@@ -80,7 +80,7 @@ async function main() {
main();
```
-Error codes are as followed:
+Error codes are as follows:
| Status Code | Error Type |
| ----------- | -------------------------- |
@@ -171,8 +171,10 @@ while (page.hasNextPage()) {
### Accessing raw Response data (e.g., headers)
The "raw" `Response` returned by `fetch()` can be accessed through the `.asResponse()` method on the `APIPromise` type that all methods return.
+This method returns as soon as the headers for a successful response are received and does not consume the response body, so you are free to write custom parsing or streaming logic.
You can also use the `.withResponse()` method to get the raw `Response` along with the parsed data.
+Unlike `.asResponse()` this method consumes the body, returning once it is parsed.
```ts
diff --git a/SECURITY.md b/SECURITY.md
index 0985c82..2b0ed90 100644
--- a/SECURITY.md
+++ b/SECURITY.md
@@ -2,9 +2,9 @@
## Reporting Security Issues
-This SDK is generated by [Stainless Software Inc](http://stainlessapi.com). Stainless takes security seriously, and encourages you to report any security vulnerability promptly so that appropriate action can be taken.
+This SDK is generated by [Stainless Software Inc](http://stainless.com). Stainless takes security seriously, and encourages you to report any security vulnerability promptly so that appropriate action can be taken.
-To report a security issue, please contact the Stainless team at security@stainlessapi.com.
+To report a security issue, please contact the Stainless team at security@stainless.com.
## Responsible Disclosure
diff --git a/api.md b/api.md
index 8e80f38..516cda9 100644
--- a/api.md
+++ b/api.md
@@ -68,6 +68,7 @@ Types:
- EnvironmentRetrieveResponse
- EnvironmentUpdateResponse
- EnvironmentDeleteResponse
+- EnvironmentCreateEnvironmentTokenResponse
- EnvironmentCreateFromProjectResponse
- EnvironmentCreateLogsTokenResponse
- EnvironmentMarkActiveResponse
@@ -81,6 +82,7 @@ Methods:
- client.environments.update({ ...params }) -> unknown
- client.environments.list({ ...params }) -> EnvironmentsEnvironmentsPage
- client.environments.delete({ ...params }) -> unknown
+- client.environments.createEnvironmentToken({ ...params }) -> EnvironmentCreateEnvironmentTokenResponse
- client.environments.createFromProject({ ...params }) -> EnvironmentCreateFromProjectResponse
- client.environments.createLogsToken({ ...params }) -> EnvironmentCreateLogsTokenResponse
- client.environments.markActive({ ...params }) -> unknown
@@ -174,7 +176,7 @@ Types:
Methods:
- client.events.list({ ...params }) -> EventListResponsesEntriesPage
-- client.events.watch({ ...params }) -> JSONLDecoder<EventWatchResponse>
+- client.events.watch({ ...params }) -> EventWatchResponse
# Groups
@@ -190,6 +192,7 @@ Methods:
Types:
+- IDTokenVersion
- IdentityExchangeTokenResponse
- IdentityGetAuthenticatedIdentityResponse
- IdentityGetIDTokenResponse
@@ -207,7 +210,7 @@ Types:
- InviteDomains
- Organization
- OrganizationMember
-- Scope
+- OrganizationTier
- OrganizationCreateResponse
- OrganizationRetrieveResponse
- OrganizationUpdateResponse
@@ -221,7 +224,6 @@ Methods:
- client.organizations.create({ ...params }) -> OrganizationCreateResponse
- client.organizations.retrieve({ ...params }) -> OrganizationRetrieveResponse
- client.organizations.update({ ...params }) -> OrganizationUpdateResponse
-- client.organizations.list({ ...params }) -> OrganizationsOrganizationsPage
- client.organizations.delete({ ...params }) -> unknown
- client.organizations.join({ ...params }) -> OrganizationJoinResponse
- client.organizations.leave({ ...params }) -> unknown
@@ -262,6 +264,19 @@ Methods:
- client.organizations.invites.retrieve({ ...params }) -> InviteRetrieveResponse
- client.organizations.invites.getSummary({ ...params }) -> InviteGetSummaryResponse
+## Policies
+
+Types:
+
+- OrganizationPolicies
+- PolicyRetrieveResponse
+- PolicyUpdateResponse
+
+Methods:
+
+- client.organizations.policies.retrieve({ ...params }) -> PolicyRetrieveResponse
+- client.organizations.policies.update({ ...params }) -> unknown
+
## SSOConfigurations
Types:
@@ -326,6 +341,8 @@ Methods:
Types:
+- LogLevel
+- MetricsConfiguration
- Runner
- RunnerCapability
- RunnerConfiguration
@@ -453,6 +470,7 @@ Methods:
Types:
- Secret
+- SecretScope
- SecretCreateResponse
- SecretDeleteResponse
- SecretGetValueResponse
@@ -466,6 +484,16 @@ Methods:
- client.secrets.getValue({ ...params }) -> SecretGetValueResponse
- client.secrets.updateValue({ ...params }) -> unknown
+# Usage
+
+Types:
+
+- EnvironmentSession
+
+Methods:
+
+- client.usage.listEnvironmentSessions({ ...params }) -> EnvironmentSessionsSessionsPage
+
# Users
Types:
@@ -479,6 +507,19 @@ Methods:
- client.users.getAuthenticatedUser({ ...params }) -> UserGetAuthenticatedUserResponse
- client.users.setSuspended({ ...params }) -> unknown
+## Dotfiles
+
+Types:
+
+- DotfilesConfiguration
+- DotfileGetResponse
+- DotfileSetResponse
+
+Methods:
+
+- client.users.dotfiles.get({ ...params }) -> DotfileGetResponse
+- client.users.dotfiles.set({ ...params }) -> unknown
+
## Pats
Types:
diff --git a/package.json b/package.json
index d59480b..00c10f8 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@gitpod/sdk",
- "version": "0.5.0",
+ "version": "0.6.0",
"description": "The official TypeScript library for the Gitpod API",
"author": "Gitpod ",
"types": "dist/index.d.ts",
@@ -17,7 +17,7 @@
"test": "./scripts/test",
"build": "./scripts/build",
"prepublishOnly": "echo 'to publish, run yarn build && (cd dist; yarn publish)' && exit 1",
- "format": "prettier --write --cache --cache-strategy metadata . !dist",
+ "format": "./scripts/format",
"prepare": "if ./scripts/utils/check-is-in-git-install.sh; then ./scripts/build && ./scripts/utils/git-swap.sh; fi",
"tsn": "ts-node -r tsconfig-paths/register",
"lint": "./scripts/lint",
@@ -32,8 +32,8 @@
"@types/node": "^20.17.6",
"@types/ssh2": "^1.15.4",
"@types/sshpk": "^1.17.4",
- "@typescript-eslint/eslint-plugin": "^8.24.0",
- "@typescript-eslint/parser": "^8.24.0",
+ "@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",
@@ -45,10 +45,17 @@
"sshpk": "^1.18.0",
"ts-jest": "^29.1.0",
"ts-node": "^10.5.0",
- "tsc-multi": "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.3/tsc-multi.tgz",
+ "tsc-multi": "https://github.com/stainless-api/tsc-multi/releases/download/v1.1.4/tsc-multi-1.1.4.tgz",
"tsconfig-paths": "^4.0.0",
- "typescript": "^4.8.2",
- "typescript-eslint": "^8.24.0"
+ "typescript": "5.8.3",
+ "typescript-eslint": "8.31.1"
+ },
+ "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": ".",
diff --git a/release-please-config.json b/release-please-config.json
index 624ed99..1ebd0bd 100644
--- a/release-please-config.json
+++ b/release-please-config.json
@@ -60,8 +60,5 @@
}
],
"release-type": "node",
- "extra-files": [
- "src/version.ts",
- "README.md"
- ]
+ "extra-files": ["src/version.ts", "README.md"]
}
diff --git a/scripts/bootstrap b/scripts/bootstrap
index 05dd47a..0af58e2 100755
--- a/scripts/bootstrap
+++ b/scripts/bootstrap
@@ -4,7 +4,7 @@ set -e
cd "$(dirname "$0")/.."
-if [ -f "Brewfile" ] && [ "$(uname -s)" = "Darwin" ]; then
+if [ -f "Brewfile" ] && [ "$(uname -s)" = "Darwin" ] && [ "$SKIP_BREW" != "1" ]; then
brew bundle check >/dev/null 2>&1 || {
echo "==> Installing Homebrew dependencies…"
brew bundle
diff --git a/scripts/build b/scripts/build
index 08bfe2e..3323742 100755
--- a/scripts/build
+++ b/scripts/build
@@ -19,29 +19,26 @@ for file in LICENSE CHANGELOG.md; do
if [ -e "${file}" ]; then cp "${file}" dist; fi
done
if [ -e "bin/cli" ]; then
- mkdir dist/bin
+ mkdir -p dist/bin
cp -p "bin/cli" dist/bin/;
fi
+if [ -e "bin/migration-config.json" ]; then
+ mkdir -p dist/bin
+ cp -p "bin/migration-config.json" dist/bin/;
+fi
# this converts the export map paths for the dist directory
# and does a few other minor things
node scripts/utils/make-dist-package-json.cjs > dist/package.json
# build to .js/.mjs/.d.ts files
npm exec tsc-multi
-# we need to add exports = module.exports = Gitpod to index.js;
-# No way to get that from index.ts because it would cause compile errors
+# we need to patch index.js so that `new module.exports()` works for cjs backwards
+# compat. No way to get that from index.ts because it would cause compile errors
# when building .mjs
node scripts/utils/fix-index-exports.cjs
-# with "moduleResolution": "nodenext", if ESM resolves to index.d.ts,
-# it'll have TS errors on the default import. But if it resolves to
-# index.d.mts the default import will work (even though both files have
-# the same export default statement)
-cp dist/index.d.ts dist/index.d.mts
cp tsconfig.dist-src.json dist/src/tsconfig.json
cp src/internal/shim-types.d.ts dist/internal/shim-types.d.ts
cp src/internal/shim-types.d.ts dist/internal/shim-types.d.mts
-mkdir -p dist/internal/polyfill
-cp src/internal/polyfill/*.{mjs,js,d.ts} dist/internal/polyfill
node scripts/utils/postprocess-files.cjs
diff --git a/scripts/format b/scripts/format
index 903b1ef..7a75640 100755
--- a/scripts/format
+++ b/scripts/format
@@ -6,3 +6,7 @@ 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/utils/postprocess-files.cjs b/scripts/utils/postprocess-files.cjs
index d16c864..deae575 100644
--- a/scripts/utils/postprocess-files.cjs
+++ b/scripts/utils/postprocess-files.cjs
@@ -50,14 +50,14 @@ async function postprocess() {
if (entry.isDirectory() && entry.name !== 'src' && entry.name !== 'internal' && entry.name !== 'bin') {
const subpath = './' + entry.name;
newExports[subpath + '/*.mjs'] = {
- default: [subpath + '/*.mjs', subpath + '/*/index.mjs'],
+ default: subpath + '/*.mjs',
};
newExports[subpath + '/*.js'] = {
- default: [subpath + '/*.js', subpath + '/*/index.js'],
+ default: subpath + '/*.js',
};
newExports[subpath + '/*'] = {
- import: [subpath + '/*.mjs', subpath + '/*/index.mjs'],
- require: [subpath + '/*.js', subpath + '/*/index.js'],
+ import: subpath + '/*.mjs',
+ require: subpath + '/*.js',
};
} else if (entry.isFile() && /\.[cm]?js$/.test(entry.name)) {
const { name, ext } = path.parse(entry.name);
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
index a7416b0..8c775ee 100644
--- a/src/api-promise.ts
+++ b/src/api-promise.ts
@@ -1,92 +1,2 @@
-// 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 extends Promise {
- private parsedPromise: Promise | undefined;
- #client: Gitpod;
-
- constructor(
- client: Gitpod,
- private responsePromise: Promise,
- private parseResponse: (
- client: Gitpod,
- props: APIResponseProps,
- ) => PromiseOrValue = defaultParseResponse,
- ) {
- super((resolve) => {
- // this is maybe a bit weird but this has to be a no-op to not implicitly
- // parse the response body; instead .then, .catch, .finally are overridden
- // to parse the response
- resolve(null as any);
- });
- this.#client = client;
- }
-
- _thenUnwrap(transform: (data: T, props: APIResponseProps) => U): APIPromise {
- return new APIPromise(this.#client, this.responsePromise, async (client, props) =>
- transform(await this.parseResponse(client, props), props),
- );
- }
-
- /**
- * Gets the raw `Response` instance instead of parsing the response
- * data.
- *
- * If you want to parse the response body but still get the `Response`
- * instance, you can use {@link withResponse()}.
- *
- * 👋 Getting the wrong TypeScript type for `Response`?
- * Try setting `"moduleResolution": "NodeNext"` or add `"lib": ["DOM"]`
- * to your `tsconfig.json`.
- */
- asResponse(): Promise {
- return this.responsePromise.then((p) => p.response);
- }
-
- /**
- * Gets the parsed response data and the raw `Response` instance.
- *
- * If you just want to get the raw `Response` instance without parsing it,
- * you can use {@link asResponse()}.
- *
- * 👋 Getting the wrong TypeScript type for `Response`?
- * Try setting `"moduleResolution": "NodeNext"` or add `"lib": ["DOM"]`
- * to your `tsconfig.json`.
- */
- async withResponse(): Promise<{ data: T; response: Response }> {
- const [data, response] = await Promise.all([this.parse(), this.asResponse()]);
- return { data, response };
- }
-
- private parse(): Promise {
- if (!this.parsedPromise) {
- this.parsedPromise = this.responsePromise.then((data) => this.parseResponse(this.#client, data));
- }
- return this.parsedPromise;
- }
-
- override then(
- onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null,
- onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null,
- ): Promise {
- return this.parse().then(onfulfilled, onrejected);
- }
-
- override catch(
- onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null,
- ): Promise {
- return this.parse().catch(onrejected);
- }
-
- override finally(onfinally?: (() => void) | undefined | null): Promise {
- return this.parse().finally(onfinally);
- }
-}
+/** @deprecated Import from ./core/api-promise instead */
+export * from './core/api-promise';
diff --git a/src/client.ts b/src/client.ts
index 9836801..d7e3523 100644
--- a/src/client.ts
+++ b/src/client.ts
@@ -1,18 +1,20 @@
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
import type { RequestInit, RequestInfo, BodyInit } from './internal/builtin-types';
-import type { HTTPMethod, PromiseOrValue, MergedRequestInit } from './internal/types';
+import type { HTTPMethod, PromiseOrValue, MergedRequestInit, FinalizedRequestInit } from './internal/types';
import { uuid4 } from './internal/utils/uuid';
-import { validatePositiveInteger, isAbsoluteURL, hasOwn } from './internal/utils/values';
+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 './error';
-import * as Pagination from './pagination';
+import * as Errors from './core/error';
+import * as Pagination from './core/pagination';
import {
AbstractPage,
type DomainVerificationsPageParams,
@@ -33,8 +35,6 @@ import {
LoginProvidersPageResponse,
type MembersPageParams,
MembersPageResponse,
- type OrganizationsPageParams,
- OrganizationsPageResponse,
type PersonalAccessTokensPageParams,
PersonalAccessTokensPageResponse,
type PoliciesPageParams,
@@ -49,16 +49,18 @@ import {
SecretsPageResponse,
type ServicesPageParams,
ServicesPageResponse,
+ type SessionsPageParams,
+ SessionsPageResponse,
type TaskExecutionsPageParams,
TaskExecutionsPageResponse,
type TasksPageParams,
TasksPageResponse,
type TokensPageParams,
TokensPageResponse,
-} from './pagination';
-import * as Uploads from './uploads';
+} from './core/pagination';
+import * as Uploads from './core/uploads';
import * as API from './resources/index';
-import { APIPromise } from './api-promise';
+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';
@@ -99,6 +101,7 @@ import {
} from './resources/events';
import { Group, GroupListParams, Groups, GroupsGroupsPage } from './resources/groups';
import {
+ IDTokenVersion,
Identity,
IdentityExchangeTokenParams,
IdentityExchangeTokenResponse,
@@ -116,11 +119,18 @@ import {
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';
@@ -128,6 +138,8 @@ import {
AdmissionLevel,
Environment,
EnvironmentActivitySignal,
+ EnvironmentCreateEnvironmentTokenParams,
+ EnvironmentCreateEnvironmentTokenResponse,
EnvironmentCreateFromProjectParams,
EnvironmentCreateFromProjectResponse,
EnvironmentCreateLogsTokenParams,
@@ -166,18 +178,16 @@ import {
OrganizationLeaveParams,
OrganizationLeaveResponse,
OrganizationListMembersParams,
- OrganizationListParams,
OrganizationMember,
OrganizationMembersMembersPage,
OrganizationRetrieveParams,
OrganizationRetrieveResponse,
OrganizationSetRoleParams,
OrganizationSetRoleResponse,
+ OrganizationTier,
OrganizationUpdateParams,
OrganizationUpdateResponse,
Organizations,
- OrganizationsOrganizationsPage,
- Scope,
} from './resources/organizations/organizations';
import {
EnvironmentInitializer,
@@ -199,6 +209,8 @@ import {
ProjectsProjectsPage,
} from './resources/projects/projects';
import {
+ LogLevel,
+ MetricsConfiguration,
Runner,
RunnerCapability,
RunnerCheckAuthenticationForHostParams,
@@ -235,48 +247,6 @@ import {
Users,
} from './resources/users/users';
-const safeJSON = (text: string) => {
- try {
- return JSON.parse(text);
- } catch (err) {
- return undefined;
- }
-};
-
-type LogFn = (message: string, ...rest: unknown[]) => void;
-export type Logger = {
- error: LogFn;
- warn: LogFn;
- info: LogFn;
- debug: LogFn;
-};
-export type LogLevel = 'off' | 'error' | 'warn' | 'info' | 'debug';
-const parseLogLevel = (
- maybeLevel: string | undefined,
- sourceName: string,
- client: Gitpod,
-): LogLevel | undefined => {
- if (!maybeLevel) {
- return undefined;
- }
- const levels: Record = {
- off: true,
- error: true,
- warn: true,
- info: true,
- debug: true,
- };
- if (hasOwn(levels, maybeLevel)) {
- return maybeLevel;
- }
- loggerFor(client).warn(
- `${sourceName} was set to ${JSON.stringify(maybeLevel)}, expected one of ${JSON.stringify(
- Object.keys(levels),
- )}`,
- );
- return undefined;
-};
-
export interface ClientOptions {
/**
* Defaults to process.env['GITPOD_API_KEY'].
@@ -350,8 +320,6 @@ export interface ClientOptions {
logger?: Logger | undefined;
}
-type FinalizedRequestInit = RequestInit & { headers: Headers };
-
/**
* API Client for interfacing with the Gitpod API.
*/
@@ -427,8 +395,8 @@ export class Gitpod {
return;
}
- protected authHeaders(opts: FinalRequestOptions): Headers | undefined {
- return new Headers({ Authorization: `Bearer ${this.bearerToken}` });
+ protected authHeaders(opts: FinalRequestOptions): NullableHeaders | undefined {
+ return buildHeaders([{ Authorization: `Bearer ${this.bearerToken}` }]);
}
/**
@@ -726,7 +694,9 @@ export class Gitpod {
const timeout = setTimeout(() => controller.abort(), ms);
- const isReadableBody = Shims.isReadableLike(options.body);
+ 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,
@@ -740,12 +710,12 @@ export class Gitpod {
fetchOptions.method = method.toUpperCase();
}
- return (
+ try {
// use undefined this binding; fetch errors if bound to something else in browser/cloudflare
- this.fetch.call(undefined, url, fetchOptions).finally(() => {
- clearTimeout(timeout);
- })
- );
+ return await this.fetch.call(undefined, url, fetchOptions);
+ } finally {
+ clearTimeout(timeout);
+ }
}
private shouldRetry(response: Response): boolean {
@@ -826,17 +796,17 @@ export class Gitpod {
}
buildRequest(
- options: FinalRequestOptions,
+ inputOptions: FinalRequestOptions,
{ retryCount = 0 }: { retryCount?: number } = {},
): { req: FinalizedRequestInit; url: string; timeout: number } {
- options = { ...options };
+ const options = { ...inputOptions };
const { method, path, query } = options;
const url = this.buildURL(path!, query as Record);
if ('timeout' in options) validatePositiveInteger('timeout', options.timeout);
options.timeout = options.timeout ?? this.timeout;
const { bodyHeaders, body } = this.buildBody({ options });
- const reqHeaders = this.buildHeaders({ options, method, bodyHeaders, retryCount });
+ const reqHeaders = this.buildHeaders({ options: inputOptions, method, bodyHeaders, retryCount });
const req: FinalizedRequestInit = {
method,
@@ -875,7 +845,7 @@ export class Gitpod {
Accept: 'application/json',
'User-Agent': this.getUserAgent(),
'X-Stainless-Retry-Count': String(retryCount),
- ...(options.timeout ? { 'X-Stainless-Timeout': String(options.timeout) } : {}),
+ ...(options.timeout ? { 'X-Stainless-Timeout': String(Math.trunc(options.timeout / 1000)) } : {}),
...getPlatformHeaders(),
},
this.authHeaders(options),
@@ -955,6 +925,7 @@ export class Gitpod {
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;
@@ -967,6 +938,7 @@ 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;
@@ -1013,12 +985,6 @@ export declare namespace Gitpod {
export import MembersPage = Pagination.MembersPage;
export { type MembersPageParams as MembersPageParams, type MembersPageResponse as MembersPageResponse };
- export import OrganizationsPage = Pagination.OrganizationsPage;
- export {
- type OrganizationsPageParams as OrganizationsPageParams,
- type OrganizationsPageResponse as OrganizationsPageResponse,
- };
-
export import PersonalAccessTokensPage = Pagination.PersonalAccessTokensPage;
export {
type PersonalAccessTokensPageParams as PersonalAccessTokensPageParams,
@@ -1040,6 +1006,9 @@ export declare namespace Gitpod {
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,
@@ -1098,6 +1067,7 @@ export declare namespace Gitpod {
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,
@@ -1109,6 +1079,7 @@ export declare namespace Gitpod {
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,
@@ -1136,6 +1107,7 @@ export declare namespace Gitpod {
export {
Identity as Identity,
+ type IDTokenVersion as IDTokenVersion,
type IdentityExchangeTokenResponse as IdentityExchangeTokenResponse,
type IdentityGetAuthenticatedIdentityResponse as IdentityGetAuthenticatedIdentityResponse,
type IdentityGetIDTokenResponse as IdentityGetIDTokenResponse,
@@ -1149,7 +1121,7 @@ export declare namespace Gitpod {
type InviteDomains as InviteDomains,
type Organization as Organization,
type OrganizationMember as OrganizationMember,
- type Scope as Scope,
+ type OrganizationTier as OrganizationTier,
type OrganizationCreateResponse as OrganizationCreateResponse,
type OrganizationRetrieveResponse as OrganizationRetrieveResponse,
type OrganizationUpdateResponse as OrganizationUpdateResponse,
@@ -1157,12 +1129,10 @@ export declare namespace Gitpod {
type OrganizationJoinResponse as OrganizationJoinResponse,
type OrganizationLeaveResponse as OrganizationLeaveResponse,
type OrganizationSetRoleResponse as OrganizationSetRoleResponse,
- type OrganizationsOrganizationsPage as OrganizationsOrganizationsPage,
type OrganizationMembersMembersPage as OrganizationMembersMembersPage,
type OrganizationCreateParams as OrganizationCreateParams,
type OrganizationRetrieveParams as OrganizationRetrieveParams,
type OrganizationUpdateParams as OrganizationUpdateParams,
- type OrganizationListParams as OrganizationListParams,
type OrganizationDeleteParams as OrganizationDeleteParams,
type OrganizationJoinParams as OrganizationJoinParams,
type OrganizationLeaveParams as OrganizationLeaveParams,
@@ -1192,6 +1162,8 @@ export declare namespace Gitpod {
export {
Runners as Runners,
+ type LogLevel as LogLevel,
+ type MetricsConfiguration as MetricsConfiguration,
type Runner as Runner,
type RunnerCapability as RunnerCapability,
type RunnerConfiguration as RunnerConfiguration,
@@ -1222,6 +1194,7 @@ export declare namespace Gitpod {
export {
Secrets as Secrets,
type Secret as Secret,
+ type SecretScope as SecretScope,
type SecretCreateResponse as SecretCreateResponse,
type SecretDeleteResponse as SecretDeleteResponse,
type SecretGetValueResponse as SecretGetValueResponse,
@@ -1234,6 +1207,13 @@ export declare namespace Gitpod {
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,
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 extends Promise {
+ private parsedPromise: Promise | undefined;
+ #client: Gitpod;
+
+ constructor(
+ client: Gitpod,
+ private responsePromise: Promise,
+ private parseResponse: (
+ client: Gitpod,
+ props: APIResponseProps,
+ ) => PromiseOrValue = defaultParseResponse,
+ ) {
+ super((resolve) => {
+ // this is maybe a bit weird but this has to be a no-op to not implicitly
+ // parse the response body; instead .then, .catch, .finally are overridden
+ // to parse the response
+ resolve(null as any);
+ });
+ this.#client = client;
+ }
+
+ _thenUnwrap(transform: (data: T, props: APIResponseProps) => U): APIPromise {
+ return new APIPromise(this.#client, this.responsePromise, async (client, props) =>
+ transform(await this.parseResponse(client, props), props),
+ );
+ }
+
+ /**
+ * Gets the raw `Response` instance instead of parsing the response
+ * data.
+ *
+ * If you want to parse the response body but still get the `Response`
+ * instance, you can use {@link withResponse()}.
+ *
+ * 👋 Getting the wrong TypeScript type for `Response`?
+ * Try setting `"moduleResolution": "NodeNext"` or add `"lib": ["DOM"]`
+ * to your `tsconfig.json`.
+ */
+ asResponse(): Promise {
+ return this.responsePromise.then((p) => p.response);
+ }
+
+ /**
+ * Gets the parsed response data and the raw `Response` instance.
+ *
+ * If you just want to get the raw `Response` instance without parsing it,
+ * you can use {@link asResponse()}.
+ *
+ * 👋 Getting the wrong TypeScript type for `Response`?
+ * Try setting `"moduleResolution": "NodeNext"` or add `"lib": ["DOM"]`
+ * to your `tsconfig.json`.
+ */
+ async withResponse(): Promise<{ data: T; response: Response }> {
+ const [data, response] = await Promise.all([this.parse(), this.asResponse()]);
+ return { data, response };
+ }
+
+ private parse(): Promise {
+ if (!this.parsedPromise) {
+ this.parsedPromise = this.responsePromise.then((data) => this.parseResponse(this.#client, data));
+ }
+ return this.parsedPromise;
+ }
+
+ override then(
+ onfulfilled?: ((value: T) => TResult1 | PromiseLike) | undefined | null,
+ onrejected?: ((reason: any) => TResult2 | PromiseLike) | undefined | null,
+ ): Promise {
+ return this.parse().then(onfulfilled, onrejected);
+ }
+
+ override catch(
+ onrejected?: ((reason: any) => TResult | PromiseLike) | undefined | null,
+ ): Promise {
+ return this.parse().catch(onrejected);
+ }
+
+ override finally(onfinally?: (() => void) | undefined | null): Promise {
+ return this.parse().finally(onfinally);
+ }
+}
diff --git a/src/core/error.ts b/src/core/error.ts
new file mode 100644
index 0000000..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;
+ 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;
+
+ if (status === 400) {
+ return new BadRequestError(status, error, message, headers);
+ }
+
+ if (status === 401) {
+ return new AuthenticationError(status, error, message, headers);
+ }
+
+ if (status === 403) {
+ return new PermissionDeniedError(status, error, message, headers);
+ }
+
+ if (status === 404) {
+ return new NotFoundError(status, error, message, headers);
+ }
+
+ if (status === 409) {
+ return new ConflictError(status, error, message, headers);
+ }
+
+ if (status === 422) {
+ return new UnprocessableEntityError(status, error, message, headers);
+ }
+
+ if (status === 429) {
+ return new RateLimitError(status, error, message, headers);
+ }
+
+ if (status >= 500) {
+ return new InternalServerError(status, error, message, headers);
+ }
+
+ return new APIError(status, error, message, headers);
+ }
+}
+
+export class APIUserAbortError extends APIError {
+ constructor({ message }: { message?: string } = {}) {
+ super(undefined, undefined, message || 'Request was aborted.', undefined);
+ }
+}
+
+export class APIConnectionError extends APIError {
+ constructor({ message, cause }: { message?: string | undefined; cause?: Error | undefined }) {
+ super(undefined, undefined, message || 'Connection error.', undefined);
+ // in some environments the 'cause' property is already declared
+ // @ts-ignore
+ if (cause) this.cause = cause;
+ }
+}
+
+export class APIConnectionTimeoutError extends APIConnectionError {
+ constructor({ message }: { message?: string } = {}) {
+ super({ message: message ?? 'Request timed out.' });
+ }
+}
+
+export class BadRequestError extends APIError<400, Headers> {}
+
+export class AuthenticationError extends APIError<401, Headers> {}
+
+export class PermissionDeniedError extends APIError<403, Headers> {}
+
+export class NotFoundError extends APIError<404, Headers> {}
+
+export class ConflictError extends APIError<409, Headers> {}
+
+export class UnprocessableEntityError extends APIError<422, Headers> {}
+
+export class RateLimitError extends APIError<429, Headers> {}
+
+export class InternalServerError extends APIError {}
diff --git a/src/core/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;
+
+export abstract class AbstractPage- implements AsyncIterable
- {
+ #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 {
+ 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 {
+ let page: this = this;
+ yield page;
+ while (page.hasNextPage()) {
+ page = await page.getNextPage();
+ yield page;
+ }
+ }
+
+ async *[Symbol.asyncIterator](): AsyncGenerator
- {
+ for await (const page of this.iterPages()) {
+ for (const item of page.getPaginatedItems()) {
+ yield item;
+ }
+ }
+ }
+}
+
+/**
+ * This subclass of Promise will resolve to an instantiated Page once the request completes.
+ *
+ * It also implements AsyncIterable to allow auto-paginating iteration on an unawaited list call, eg:
+ *
+ * for await (const item of client.items.list()) {
+ * console.log(item)
+ * }
+ */
+export class PagePromise<
+ PageClass extends AbstractPage
- ,
+ Item = ReturnType[number],
+ >
+ extends APIPromise
+ implements AsyncIterable
-
+{
+ constructor(
+ client: Gitpod,
+ request: Promise,
+ Page: new (...args: ConstructorParameters) => 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
- {
+ domainVerifications: Array
- ;
+
+ pagination: DomainVerificationsPageResponse.Pagination;
+}
+
+export namespace DomainVerificationsPageResponse {
+ export interface Pagination {
+ nextToken?: string;
+ }
+}
+
+export interface DomainVerificationsPageParams {
+ pageSize?: number;
+
+ token?: string;
+}
+
+export class DomainVerificationsPage
-
+ extends AbstractPage
-
+ implements DomainVerificationsPageResponse
-
+{
+ domainVerifications: Array
- ;
+
+ pagination: DomainVerificationsPageResponse.Pagination;
+
+ constructor(
+ client: Gitpod,
+ response: Response,
+ body: DomainVerificationsPageResponse
- ,
+ 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
- {
+ editors: Array
- ;
+
+ pagination: EditorsPageResponse.Pagination;
+}
+
+export namespace EditorsPageResponse {
+ export interface Pagination {
+ nextToken?: string;
+ }
+}
+
+export interface EditorsPageParams {
+ pageSize?: number;
+
+ token?: string;
+}
+
+export class EditorsPage
- extends AbstractPage
- implements EditorsPageResponse
- {
+ editors: Array
- ;
+
+ pagination: EditorsPageResponse.Pagination;
+
+ constructor(
+ client: Gitpod,
+ response: Response,
+ body: EditorsPageResponse
- ,
+ 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
- {
+ entries: Array
- ;
+
+ pagination: EntriesPageResponse.Pagination;
+}
+
+export namespace EntriesPageResponse {
+ export interface Pagination {
+ nextToken?: string;
+ }
+}
+
+export interface EntriesPageParams {
+ pageSize?: number;
+
+ token?: string;
+}
+
+export class EntriesPage
- extends AbstractPage
- implements EntriesPageResponse
- {
+ entries: Array
- ;
+
+ pagination: EntriesPageResponse.Pagination;
+
+ constructor(
+ client: Gitpod,
+ response: Response,
+ body: EntriesPageResponse
- ,
+ 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
- {
+ environmentClasses: Array
- ;
+
+ pagination: EnvironmentClassesPageResponse.Pagination;
+}
+
+export namespace EnvironmentClassesPageResponse {
+ export interface Pagination {
+ nextToken?: string;
+ }
+}
+
+export interface EnvironmentClassesPageParams {
+ pageSize?: number;
+
+ token?: string;
+}
+
+export class EnvironmentClassesPage
-
+ extends AbstractPage
-
+ implements EnvironmentClassesPageResponse
-
+{
+ environmentClasses: Array
- ;
+
+ pagination: EnvironmentClassesPageResponse.Pagination;
+
+ constructor(
+ client: Gitpod,
+ response: Response,
+ body: EnvironmentClassesPageResponse
- ,
+ 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
- {
+ environments: Array
- ;
+
+ pagination: EnvironmentsPageResponse.Pagination;
+}
+
+export namespace EnvironmentsPageResponse {
+ export interface Pagination {
+ nextToken?: string;
+ }
+}
+
+export interface EnvironmentsPageParams {
+ pageSize?: number;
+
+ token?: string;
+}
+
+export class EnvironmentsPage
- extends AbstractPage
- implements EnvironmentsPageResponse
- {
+ environments: Array
- ;
+
+ pagination: EnvironmentsPageResponse.Pagination;
+
+ constructor(
+ client: Gitpod,
+ response: Response,
+ body: EnvironmentsPageResponse
- ,
+ 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
- {
+ groups: Array
- ;
+
+ pagination: GroupsPageResponse.Pagination;
+}
+
+export namespace GroupsPageResponse {
+ export interface Pagination {
+ nextToken?: string;
+ }
+}
+
+export interface GroupsPageParams {
+ pageSize?: number;
+
+ token?: string;
+}
+
+export class GroupsPage
- extends AbstractPage
- implements GroupsPageResponse
- {
+ groups: Array
- ;
+
+ pagination: GroupsPageResponse.Pagination;
+
+ constructor(
+ client: Gitpod,
+ response: Response,
+ body: GroupsPageResponse
- ,
+ 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
- {
+ integrations: Array
- ;
+
+ pagination: IntegrationsPageResponse.Pagination;
+}
+
+export namespace IntegrationsPageResponse {
+ export interface Pagination {
+ nextToken?: string;
+ }
+}
+
+export interface IntegrationsPageParams {
+ pageSize?: number;
+
+ token?: string;
+}
+
+export class IntegrationsPage
- extends AbstractPage
- implements IntegrationsPageResponse
- {
+ integrations: Array
- ;
+
+ pagination: IntegrationsPageResponse.Pagination;
+
+ constructor(
+ client: Gitpod,
+ response: Response,
+ body: IntegrationsPageResponse
- ,
+ 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
- {
+ loginProviders: Array
- ;
+
+ pagination: LoginProvidersPageResponse.Pagination;
+}
+
+export namespace LoginProvidersPageResponse {
+ export interface Pagination {
+ nextToken?: string;
+ }
+}
+
+export interface LoginProvidersPageParams {
+ pageSize?: number;
+
+ token?: string;
+}
+
+export class LoginProvidersPage
- extends AbstractPage
- implements LoginProvidersPageResponse
- {
+ loginProviders: Array
- ;
+
+ pagination: LoginProvidersPageResponse.Pagination;
+
+ constructor(
+ client: Gitpod,
+ response: Response,
+ body: LoginProvidersPageResponse
- ,
+ 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
- {
+ members: Array
- ;
+
+ pagination: MembersPageResponse.Pagination;
+}
+
+export namespace MembersPageResponse {
+ export interface Pagination {
+ nextToken?: string;
+ }
+}
+
+export interface MembersPageParams {
+ pageSize?: number;
+
+ token?: string;
+}
+
+export class MembersPage
- extends AbstractPage
- implements MembersPageResponse
- {
+ members: Array
- ;
+
+ pagination: MembersPageResponse.Pagination;
+
+ constructor(
+ client: Gitpod,
+ response: Response,
+ body: MembersPageResponse
- ,
+ 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
- {
+ pagination: PersonalAccessTokensPageResponse.Pagination;
+
+ personalAccessTokens: Array
- ;
+}
+
+export namespace PersonalAccessTokensPageResponse {
+ export interface Pagination {
+ nextToken?: string;
+ }
+}
+
+export interface PersonalAccessTokensPageParams {
+ pageSize?: number;
+
+ token?: string;
+}
+
+export class PersonalAccessTokensPage
-
+ extends AbstractPage
-
+ implements PersonalAccessTokensPageResponse
-
+{
+ pagination: PersonalAccessTokensPageResponse.Pagination;
+
+ personalAccessTokens: Array
- ;
+
+ constructor(
+ client: Gitpod,
+ response: Response,
+ body: PersonalAccessTokensPageResponse
- ,
+ 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
- {
+ pagination: PoliciesPageResponse.Pagination;
+
+ policies: Array
- ;
+}
+
+export namespace PoliciesPageResponse {
+ export interface Pagination {
+ nextToken?: string;
+ }
+}
+
+export interface PoliciesPageParams {
+ pageSize?: number;
+
+ token?: string;
+}
+
+export class PoliciesPage
- extends AbstractPage
- implements PoliciesPageResponse
- {
+ pagination: PoliciesPageResponse.Pagination;
+
+ policies: Array
- ;
+
+ constructor(
+ client: Gitpod,
+ response: Response,
+ body: PoliciesPageResponse
- ,
+ 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
- {
+ pagination: ProjectsPageResponse.Pagination;
+
+ projects: Array
- ;
+}
+
+export namespace ProjectsPageResponse {
+ export interface Pagination {
+ nextToken?: string;
+ }
+}
+
+export interface ProjectsPageParams {
+ pageSize?: number;
+
+ token?: string;
+}
+
+export class ProjectsPage
- extends AbstractPage
- implements ProjectsPageResponse
- {
+ pagination: ProjectsPageResponse.Pagination;
+
+ projects: Array
- ;
+
+ constructor(
+ client: Gitpod,
+ response: Response,
+ body: ProjectsPageResponse
- ,
+ 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
- {
+ pagination: RunnersPageResponse.Pagination;
+
+ runners: Array
- ;
+}
+
+export namespace RunnersPageResponse {
+ export interface Pagination {
+ nextToken?: string;
+ }
+}
+
+export interface RunnersPageParams {
+ pageSize?: number;
+
+ token?: string;
+}
+
+export class RunnersPage
- extends AbstractPage
- implements RunnersPageResponse
- {
+ pagination: RunnersPageResponse.Pagination;
+
+ runners: Array
- ;
+
+ constructor(
+ client: Gitpod,
+ response: Response,
+ body: RunnersPageResponse
- ,
+ 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
- {
+ pagination: SecretsPageResponse.Pagination;
+
+ secrets: Array
- ;
+}
+
+export namespace SecretsPageResponse {
+ export interface Pagination {
+ nextToken?: string;
+ }
+}
+
+export interface SecretsPageParams {
+ pageSize?: number;
+
+ token?: string;
+}
+
+export class SecretsPage
- extends AbstractPage
- implements SecretsPageResponse
- {
+ pagination: SecretsPageResponse.Pagination;
+
+ secrets: Array
- ;
+
+ constructor(
+ client: Gitpod,
+ response: Response,
+ body: SecretsPageResponse
- ,
+ 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
- {
+ pagination: ServicesPageResponse.Pagination;
+
+ services: Array
- ;
+}
+
+export namespace ServicesPageResponse {
+ export interface Pagination {
+ nextToken?: string;
+ }
+}
+
+export interface ServicesPageParams {
+ pageSize?: number;
+
+ token?: string;
+}
+
+export class ServicesPage
- extends AbstractPage
- implements ServicesPageResponse
- {
+ pagination: ServicesPageResponse.Pagination;
+
+ services: Array
- ;
+
+ constructor(
+ client: Gitpod,
+ response: Response,
+ body: ServicesPageResponse
- ,
+ 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
- {
+ pagination: SessionsPageResponse.Pagination;
+
+ sessions: Array
- ;
+}
+
+export namespace SessionsPageResponse {
+ export interface Pagination {
+ nextToken?: string;
+ }
+}
+
+export interface SessionsPageParams {
+ pageSize?: number;
+
+ token?: string;
+}
+
+export class SessionsPage
- extends AbstractPage
- implements SessionsPageResponse
- {
+ pagination: SessionsPageResponse.Pagination;
+
+ sessions: Array
- ;
+
+ constructor(
+ client: Gitpod,
+ response: Response,
+ body: SessionsPageResponse
- ,
+ 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
- {
+ pagination: SSOConfigurationsPageResponse.Pagination;
+
+ ssoConfigurations: Array
- ;
+}
+
+export namespace SSOConfigurationsPageResponse {
+ export interface Pagination {
+ nextToken?: string;
+ }
+}
+
+export interface SSOConfigurationsPageParams {
+ pageSize?: number;
+
+ token?: string;
+}
+
+export class SSOConfigurationsPage
-
+ extends AbstractPage
-
+ implements SSOConfigurationsPageResponse
-
+{
+ pagination: SSOConfigurationsPageResponse.Pagination;
+
+ ssoConfigurations: Array
- ;
+
+ constructor(
+ client: Gitpod,
+ response: Response,
+ body: SSOConfigurationsPageResponse
- ,
+ 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
- {
+ pagination: TaskExecutionsPageResponse.Pagination;
+
+ taskExecutions: Array
- ;
+}
+
+export namespace TaskExecutionsPageResponse {
+ export interface Pagination {
+ nextToken?: string;
+ }
+}
+
+export interface TaskExecutionsPageParams {
+ pageSize?: number;
+
+ token?: string;
+}
+
+export class TaskExecutionsPage
- extends AbstractPage
- implements TaskExecutionsPageResponse
- {
+ pagination: TaskExecutionsPageResponse.Pagination;
+
+ taskExecutions: Array
- ;
+
+ constructor(
+ client: Gitpod,
+ response: Response,
+ body: TaskExecutionsPageResponse
- ,
+ 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
- {
+ pagination: TasksPageResponse.Pagination;
+
+ tasks: Array
- ;
+}
+
+export namespace TasksPageResponse {
+ export interface Pagination {
+ nextToken?: string;
+ }
+}
+
+export interface TasksPageParams {
+ pageSize?: number;
+
+ token?: string;
+}
+
+export class TasksPage
- extends AbstractPage
- implements TasksPageResponse
- {
+ pagination: TasksPageResponse.Pagination;
+
+ tasks: Array
- ;
+
+ constructor(
+ client: Gitpod,
+ response: Response,
+ body: TasksPageResponse
- ,
+ 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
- {
+ pagination: TokensPageResponse.Pagination;
+
+ tokens: Array
- ;
+}
+
+export namespace TokensPageResponse {
+ export interface Pagination {
+ nextToken?: string;
+ }
+}
+
+export interface TokensPageParams {
+ pageSize?: number;
+
+ token?: string;
+}
+
+export class TokensPage
- extends AbstractPage
- implements TokensPageResponse
- {
+ pagination: TokensPageResponse.Pagination;
+
+ tokens: Array
- ;
+
+ constructor(
+ client: Gitpod,
+ response: Response,
+ body: TokensPageResponse
- ,
+ 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
index 67145c6..fc55f46 100644
--- a/src/error.ts
+++ b/src/error.ts
@@ -1,140 +1,2 @@
-// 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;
- 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;
-
- if (status === 400) {
- return new BadRequestError(status, error, message, headers);
- }
-
- if (status === 401) {
- return new AuthenticationError(status, error, message, headers);
- }
-
- if (status === 403) {
- return new PermissionDeniedError(status, error, message, headers);
- }
-
- if (status === 404) {
- return new NotFoundError(status, error, message, headers);
- }
-
- if (status === 409) {
- return new ConflictError(status, error, message, headers);
- }
-
- if (status === 422) {
- return new UnprocessableEntityError(status, error, message, headers);
- }
-
- if (status === 429) {
- return new RateLimitError(status, error, message, headers);
- }
-
- if (status >= 500) {
- return new InternalServerError(status, error, message, headers);
- }
-
- return new APIError(status, error, message, headers);
- }
-}
-
-export class APIUserAbortError extends APIError {
- constructor({ message }: { message?: string } = {}) {
- super(undefined, undefined, message || 'Request was aborted.', undefined);
- }
-}
-
-export class APIConnectionError extends APIError {
- constructor({ message, cause }: { message?: string | undefined; cause?: Error | undefined }) {
- super(undefined, undefined, message || 'Connection error.', undefined);
- // in some environments the 'cause' property is already declared
- // @ts-ignore
- if (cause) this.cause = cause;
- }
-}
-
-export class APIConnectionTimeoutError extends APIConnectionError {
- constructor({ message }: { message?: string } = {}) {
- super({ message: message ?? 'Request timed out.' });
- }
-}
-
-export class BadRequestError extends APIError<400, Headers> {}
-
-export class AuthenticationError extends APIError<401, Headers> {}
-
-export class PermissionDeniedError extends APIError<403, Headers> {}
-
-export class NotFoundError extends APIError<404, Headers> {}
-
-export class ConflictError extends APIError<409, Headers> {}
-
-export class UnprocessableEntityError extends APIError<422, Headers> {}
-
-export class RateLimitError extends APIError<429, Headers> {}
-
-export class InternalServerError extends APIError {}
+/** @deprecated Import from ./core/error instead */
+export * from './core/error';
diff --git a/src/index.ts b/src/index.ts
index 2b3917a..0eaf4c8 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -2,10 +2,10 @@
export { Gitpod as default } from './client';
-export { type Uploadable, toFile } from './uploads';
-export { APIPromise } from './api-promise';
+export { type Uploadable, toFile } from './core/uploads';
+export { APIPromise } from './core/api-promise';
export { Gitpod, type ClientOptions } from './client';
-export { PagePromise } from './pagination';
+export { PagePromise } from './core/pagination';
export {
GitpodError,
APIError,
@@ -20,4 +20,4 @@ export {
InternalServerError,
PermissionDeniedError,
UnprocessableEntityError,
-} from './error';
+} 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
index b2e598a..c23d3bd 100644
--- a/src/internal/builtin-types.ts
+++ b/src/internal/builtin-types.ts
@@ -39,9 +39,23 @@ type _HeadersInit = RequestInit['headers'];
*/
type _BodyInit = RequestInit['body'];
+/**
+ * An alias to the builtin `Array` type so we can
+ * easily alias it in import statements if there are name clashes.
+ */
+type _Array = Array;
+
+/**
+ * An alias to the builtin `Record` type so we can
+ * easily alias it in import statements if there are name clashes.
+ */
+type _Record = Record;
+
export type {
+ _Array as Array,
_BodyInit as BodyInit,
_HeadersInit as HeadersInit,
+ _Record as Record,
_RequestInfo as RequestInfo,
_RequestInit as RequestInit,
_Response as Response,
diff --git a/src/internal/decoders/jsonl.ts b/src/internal/decoders/jsonl.ts
index cb40d92..79ec5f8 100644
--- a/src/internal/decoders/jsonl.ts
+++ b/src/internal/decoders/jsonl.ts
@@ -1,4 +1,4 @@
-import { GitpodError } from '../../error';
+import { GitpodError } from '../../core/error';
import { ReadableStreamToAsyncIterable } from '../shims';
import { LineDecoder, type Bytes } from './line';
diff --git a/src/internal/decoders/line.ts b/src/internal/decoders/line.ts
index 0295286..b3bfa97 100644
--- a/src/internal/decoders/line.ts
+++ b/src/internal/decoders/line.ts
@@ -1,4 +1,4 @@
-import { GitpodError } from '../../error';
+import { concatBytes, decodeUTF8, encodeUTF8 } from '../utils/bytes';
export type Bytes = string | ArrayBuffer | Uint8Array | null | undefined;
@@ -13,16 +13,11 @@ export class LineDecoder {
static NEWLINE_CHARS = new Set(['\n', '\r']);
static NEWLINE_REGEXP = /\r\n|[\n\r]/g;
- buffer: Uint8Array;
+ #buffer: Uint8Array;
#carriageReturnIndex: number | null;
- textDecoder:
- | undefined
- | {
- decode(buffer: Uint8Array | ArrayBuffer): string;
- };
constructor() {
- this.buffer = new Uint8Array();
+ this.#buffer = new Uint8Array();
this.#carriageReturnIndex = null;
}
@@ -33,17 +28,14 @@ export class LineDecoder {
const binaryChunk =
chunk instanceof ArrayBuffer ? new Uint8Array(chunk)
- : typeof chunk === 'string' ? new TextEncoder().encode(chunk)
+ : typeof chunk === 'string' ? encodeUTF8(chunk)
: chunk;
- let newData = new Uint8Array(this.buffer.length + binaryChunk.length);
- newData.set(this.buffer);
- newData.set(binaryChunk, this.buffer.length);
- this.buffer = newData;
+ this.#buffer = concatBytes([this.#buffer, binaryChunk]);
const lines: string[] = [];
let patternIndex;
- while ((patternIndex = findNewlineIndex(this.buffer, this.#carriageReturnIndex)) != null) {
+ while ((patternIndex = findNewlineIndex(this.#buffer, this.#carriageReturnIndex)) != null) {
if (patternIndex.carriage && this.#carriageReturnIndex == null) {
// skip until we either get a corresponding `\n`, a new `\r` or nothing
this.#carriageReturnIndex = patternIndex.index;
@@ -55,8 +47,8 @@ export class LineDecoder {
this.#carriageReturnIndex != null &&
(patternIndex.index !== this.#carriageReturnIndex + 1 || patternIndex.carriage)
) {
- lines.push(this.decodeText(this.buffer.slice(0, this.#carriageReturnIndex - 1)));
- this.buffer = this.buffer.slice(this.#carriageReturnIndex);
+ lines.push(decodeUTF8(this.#buffer.subarray(0, this.#carriageReturnIndex - 1)));
+ this.#buffer = this.#buffer.subarray(this.#carriageReturnIndex);
this.#carriageReturnIndex = null;
continue;
}
@@ -64,55 +56,18 @@ export class LineDecoder {
const endIndex =
this.#carriageReturnIndex !== null ? patternIndex.preceding - 1 : patternIndex.preceding;
- const line = this.decodeText(this.buffer.slice(0, endIndex));
+ const line = decodeUTF8(this.#buffer.subarray(0, endIndex));
lines.push(line);
- this.buffer = this.buffer.slice(patternIndex.index);
+ this.#buffer = this.#buffer.subarray(patternIndex.index);
this.#carriageReturnIndex = null;
}
return lines;
}
- decodeText(bytes: Bytes): string {
- if (bytes == null) return '';
- if (typeof bytes === 'string') return bytes;
-
- // Node:
- if (typeof (globalThis as any).Buffer !== 'undefined') {
- if (bytes instanceof (globalThis as any).Buffer) {
- return bytes.toString();
- }
- if (bytes instanceof Uint8Array) {
- return (globalThis as any).Buffer.from(bytes).toString();
- }
-
- throw new GitpodError(
- `Unexpected: received non-Uint8Array (${bytes.constructor.name}) stream chunk in an environment with a global "Buffer" defined, which this library assumes to be Node. Please report this error.`,
- );
- }
-
- // Browser
- if (typeof (globalThis as any).TextDecoder !== 'undefined') {
- if (bytes instanceof Uint8Array || bytes instanceof ArrayBuffer) {
- this.textDecoder ??= new (globalThis as any).TextDecoder('utf8');
- return this.textDecoder!.decode(bytes);
- }
-
- throw new GitpodError(
- `Unexpected: received non-Uint8Array/ArrayBuffer (${
- (bytes as any).constructor.name
- }) in a web platform. Please report this error.`,
- );
- }
-
- throw new GitpodError(
- `Unexpected: neither Buffer nor TextDecoder are available as globals. Please report this error.`,
- );
- }
-
flush(): string[] {
- if (!this.buffer.length) {
+ if (!this.#buffer.length) {
return [];
}
return this.decode('\n');
diff --git a/src/internal/errors.ts b/src/internal/errors.ts
index 653a6ec..82c7b14 100644
--- a/src/internal/errors.ts
+++ b/src/internal/errors.ts
@@ -22,7 +22,7 @@ export const castToError = (err: any): Error => {
// @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;
- throw error;
+ return error;
}
} catch {}
try {
diff --git a/src/internal/headers.ts b/src/internal/headers.ts
index a110a12..8659dde 100644
--- a/src/internal/headers.ts
+++ b/src/internal/headers.ts
@@ -3,7 +3,7 @@
type HeaderValue = string | undefined | null;
export type HeadersLike =
| Headers
- | readonly [string, HeaderValue][]
+ | readonly HeaderValue[][]
| Record
| undefined
| null
@@ -40,7 +40,7 @@ function* iterateHeaders(headers: HeadersLike): IterableIterator;
+ let iter: Iterable;
if (headers instanceof Headers) {
iter = headers.entries();
} else if (isArray(headers)) {
@@ -51,6 +51,7 @@ function* iterateHeaders(headers: HeadersLike): IterableIterator(client: Gitpod, props: APIResponse
}
const contentType = response.headers.get('content-type');
- const isJSON =
- contentType?.includes('application/json') || contentType?.includes('application/vnd.api+json');
+ 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();
-
- // TODO handle blob, arraybuffer, other content types, etc.
return text as unknown as T;
})();
loggerFor(client).debug(
diff --git a/src/internal/polyfill/crypto.node.d.ts b/src/internal/polyfill/crypto.node.d.ts
deleted file mode 100644
index dc7caac..0000000
--- a/src/internal/polyfill/crypto.node.d.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-export declare const crypto: {
- /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Crypto/getRandomValues) */
- getRandomValues(array: T): T;
- /**
- * Available only in secure contexts.
- *
- * [MDN Reference](https://developer.mozilla.org/docs/Web/API/Crypto/randomUUID)
- */
- randomUUID?: () => string;
-};
diff --git a/src/internal/polyfill/crypto.node.js b/src/internal/polyfill/crypto.node.js
deleted file mode 100644
index 83062a3..0000000
--- a/src/internal/polyfill/crypto.node.js
+++ /dev/null
@@ -1,11 +0,0 @@
-if (typeof require !== 'undefined') {
- if (globalThis.crypto) {
- exports.crypto = globalThis.crypto;
- } else {
- try {
- // Use [require][0](...) and not require(...) so bundlers don't try to bundle the
- // crypto module.
- exports.crypto = [require][0]('node:crypto').webcrypto;
- } catch (e) {}
- }
-}
diff --git a/src/internal/polyfill/crypto.node.mjs b/src/internal/polyfill/crypto.node.mjs
deleted file mode 100644
index 24c6f3b..0000000
--- a/src/internal/polyfill/crypto.node.mjs
+++ /dev/null
@@ -1,2 +0,0 @@
-import * as mod from './crypto.node.js';
-export const crypto = globalThis.crypto || mod.crypto;
diff --git a/src/internal/polyfill/file.node.d.ts b/src/internal/polyfill/file.node.d.ts
deleted file mode 100644
index b2a59bf..0000000
--- a/src/internal/polyfill/file.node.d.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-/**
- * This file polyfills the global `File` object for you if it's not already defined
- * when running on Node.js
- *
- * This is only needed on Node.js v18 & v19. Newer versions already define `File`
- * as a global.
- */
-
-export {};
diff --git a/src/internal/polyfill/file.node.js b/src/internal/polyfill/file.node.js
deleted file mode 100644
index eba997e..0000000
--- a/src/internal/polyfill/file.node.js
+++ /dev/null
@@ -1,17 +0,0 @@
-/**
- * This file polyfills the global `File` object for you if it's not already defined
- * when running on Node.js
- *
- * This is only needed on Node.js v18 & v19. Newer versions already define `File`
- * as a global.
- */
-
-if (typeof require !== 'undefined') {
- if (!globalThis.File) {
- try {
- // Use [require][0](...) and not require(...) so bundlers don't try to bundle the
- // buffer module.
- globalThis.File = [require][0]('node:buffer').File;
- } catch (e) {}
- }
-}
diff --git a/src/internal/polyfill/file.node.mjs b/src/internal/polyfill/file.node.mjs
deleted file mode 100644
index 520dcb8..0000000
--- a/src/internal/polyfill/file.node.mjs
+++ /dev/null
@@ -1,9 +0,0 @@
-/**
- * This file polyfills the global `File` object for you if it's not already defined
- * when running on Node.js
- *
- * This is only needed on Node.js v18 & v19. Newer versions already define `File`
- * as a global.
- */
-
-import './file.node.js';
diff --git a/src/internal/shims.ts b/src/internal/shims.ts
index cb91e94..95b03fb 100644
--- a/src/internal/shims.ts
+++ b/src/internal/shims.ts
@@ -20,62 +20,6 @@ export function getDefaultFetch(): Fetch {
);
}
-/**
- * A minimal copy of the NodeJS `stream.Readable` class so that we can
- * accept the NodeJS types in certain places, e.g. file uploads
- *
- * https://nodejs.org/api/stream.html#class-streamreadable
- */
-export interface ReadableLike {
- readable: boolean;
- readonly readableEnded: boolean;
- readonly readableFlowing: boolean | null;
- readonly readableHighWaterMark: number;
- readonly readableLength: number;
- readonly readableObjectMode: boolean;
- destroyed: boolean;
- read(size?: number): any;
- pause(): this;
- resume(): this;
- isPaused(): boolean;
- destroy(error?: Error): this;
- [Symbol.asyncIterator](): AsyncIterableIterator;
-}
-
-/**
- * Determines if the given value looks like a NodeJS `stream.Readable`
- * object and that it is readable, i.e. has not been consumed.
- *
- * https://nodejs.org/api/stream.html#class-streamreadable
- */
-export function isReadableLike(value: any) {
- // We declare our own class of Readable here, so it's not feasible to
- // do an 'instanceof' check. Instead, check for Readable-like properties.
- return !!value && value.readable === true && typeof value.read === 'function';
-}
-
-/**
- * A minimal copy of the NodeJS `fs.ReadStream` class for usage within file uploads.
- *
- * https://nodejs.org/api/fs.html#class-fsreadstream
- */
-export interface FsReadStreamLike extends ReadableLike {
- path: {}; // real type is string | Buffer but we can't reference `Buffer` here
-}
-
-/**
- * Determines if the given value looks like a NodeJS `fs.ReadStream`
- * object.
- *
- * This just checks if the object matches our `Readable` interface
- * and defines a `path` property, there may be false positives.
- *
- * https://nodejs.org/api/fs.html#class-fsreadstream
- */
-export function isFsReadStreamLike(value: any): value is FsReadStreamLike {
- return isReadableLike(value) && 'path' in value;
-}
-
type ReadableStreamArgs = ConstructorParameters;
export function makeReadableStream(...args: ReadableStreamArgs): ReadableStream {
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(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;
+
+// The infer is to make TS show it as a nice union type,
+// instead of literally `ConstructorParameters[0]`
+type FallbackBlobSource = ConstructorParameters[0] extends infer T ? T : never;
+/**
+ * A [`File`](https://developer.mozilla.org/en-US/docs/Web/API/File) provides information about files.
+ */
+declare class FallbackFile extends Blob {
+ constructor(sources: FallbackBlobSource, fileName: string, options?: any);
+ /**
+ * The name of the `File`.
+ */
+ readonly name: string;
+ /**
+ * The last modified date of the `File`.
+ */
+ readonly lastModified: number;
+}
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;
+ /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Blob/slice) */
+ slice(start?: number, end?: number): BlobLike;
+}
+
+/**
+ * This check adds the arrayBuffer() method type because it is available and used at runtime
+ */
+const isBlobLike = (value: any): value is BlobLike & { arrayBuffer(): Promise } =>
+ value != null &&
+ typeof value === 'object' &&
+ typeof value.size === 'number' &&
+ typeof value.type === 'string' &&
+ typeof value.text === 'function' &&
+ typeof value.slice === 'function' &&
+ typeof value.arrayBuffer === 'function';
+
+/**
+ * Intended to match DOM File, node:buffer File, undici File, etc.
+ */
+interface FileLike extends BlobLike {
+ /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/File/lastModified) */
+ readonly lastModified: number;
+ /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/File/name) */
+ readonly name?: string | undefined;
+}
+
+/**
+ * This check adds the arrayBuffer() method type because it is available and used at runtime
+ */
+const isFileLike = (value: any): value is FileLike & { arrayBuffer(): Promise } =>
+ value != null &&
+ typeof value === 'object' &&
+ typeof value.name === 'string' &&
+ typeof value.lastModified === 'number' &&
+ isBlobLike(value);
+
+/**
+ * Intended to match DOM Response, node-fetch Response, undici Response, etc.
+ */
+export interface ResponseLike {
+ url: string;
+ blob(): Promise;
+}
+
+const isResponseLike = (value: any): value is ResponseLike =>
+ value != null &&
+ typeof value === 'object' &&
+ typeof value.url === 'string' &&
+ typeof value.blob === 'function';
+
+export type ToFileInput =
+ | FileLike
+ | ResponseLike
+ | Exclude
+ | AsyncIterable;
+
+/**
+ * Helper for creating a {@link File} to pass to an SDK upload method from a variety of different data formats
+ * @param value the raw content of the file. Can be an {@link Uploadable}, {@link BlobLikePart}, or {@link AsyncIterable} of {@link BlobLikePart}s
+ * @param {string=} name the name of the file. If omitted, toFile will try to determine a file name from bits if possible
+ * @param {Object=} options additional properties
+ * @param {string=} options.type the MIME type of the content
+ * @param {number=} options.lastModified the last modified timestamp
+ * @returns a {@link File} with the given properties
+ */
+export async function toFile(
+ value: ToFileInput | PromiseLike,
+ name?: string | null | undefined,
+ options?: FilePropertyBag | undefined,
+): Promise {
+ // If it's a promise, resolve it.
+ value = await value;
+
+ // If we've been given a `File` we don't need to do anything
+ if (isFileLike(value)) {
+ if (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): Promise> {
+ let parts: Array = [];
+ if (
+ typeof value === 'string' ||
+ ArrayBuffer.isView(value) || // includes Uint8Array, Buffer, etc.
+ value instanceof ArrayBuffer
+ ) {
+ parts.push(value);
+ } else if (isBlobLike(value)) {
+ parts.push(value instanceof Blob ? value : await value.arrayBuffer());
+ } else if (
+ isAsyncIterable(value) // includes Readable, ReadableStream, etc.
+ ) {
+ for await (const chunk of value) {
+ parts.push(...(await getBytes(chunk as BlobLikePart))); // TODO, consider validating?
+ }
+ } else {
+ const constructor = value?.constructor?.name;
+ throw new Error(
+ `Unexpected data type: ${typeof value}${
+ constructor ? `; constructor: ${constructor}` : ''
+ }${propsForError(value)}`,
+ );
+ }
+
+ return parts;
+}
+
+function propsForError(value: unknown): string {
+ if (typeof value !== 'object' || value === null) return '';
+ const props = Object.getOwnPropertyNames(value);
+ return `; props: [${props.map((p) => `"${p}"`).join(', ')}]`;
+}
diff --git a/src/internal/types.ts b/src/internal/types.ts
index 50c16e9..d7928cd 100644
--- a/src/internal/types.ts
+++ b/src/internal/types.ts
@@ -5,15 +5,9 @@ export type HTTPMethod = 'get' | 'post' | 'put' | 'patch' | 'delete';
export type KeysEnum = { [P in keyof Required]: true };
+export type FinalizedRequestInit = RequestInit & { headers: Headers };
+
type NotAny = [unknown] extends [T] ? never : T;
-type Literal = PropertyKey extends T ? never : T;
-type MappedLiteralKeys = T extends any ? Literal : never;
-type MappedIndex =
- T extends any ?
- K extends keyof T ?
- T[K]
- : never
- : never;
/**
* Some environments overload the global fetch function, and Parameters only gets the last signature.
@@ -93,6 +87,6 @@ type RequestInits =
* This type contains `RequestInit` options that may be available on the current runtime,
* including per-platform extensions like `dispatcher`, `agent`, `client`, etc.
*/
-export type MergedRequestInit = {
- [K in MappedLiteralKeys]?: MappedIndex | undefined;
-};
+export type MergedRequestInit = RequestInits &
+ /** We don't include these in the types as they'll be overridden for every request. */
+ Partial>;
diff --git a/src/internal/uploads.ts b/src/internal/uploads.ts
index ee2029c..fa0627a 100644
--- a/src/internal/uploads.ts
+++ b/src/internal/uploads.ts
@@ -1,11 +1,16 @@
import { type RequestOptions } from './request-options';
import type { FilePropertyBag, Fetch } from './builtin-types';
-import { isFsReadStreamLike, type FsReadStreamLike } from './shims';
import type { Gitpod } from '../client';
-import './polyfill/file.node.js';
+import { type File, getFile } from './shims/file';
+import { ReadableStreamFrom } from './shims';
-type BlobLikePart = string | ArrayBuffer | ArrayBufferView | BlobLike | DataView;
-type BlobPart = string | ArrayBuffer | ArrayBufferView | Blob | DataView;
+export type BlobPart = string | ArrayBuffer | ArrayBufferView | Blob | DataView;
+type FsReadStream = AsyncIterable & { path: string | { toString(): string } };
+
+// https://github.com/oven-sh/bun/issues/5980
+interface BunFile extends Blob {
+ readonly name?: string | undefined;
+}
/**
* Typically, this is a native "File" class.
@@ -16,188 +21,38 @@ type BlobPart = string | ArrayBuffer | ArrayBufferView | Blob | DataView;
* For convenience, you can also pass a fetch Response, or in Node,
* the result of fs.createReadStream().
*/
-export type Uploadable = FileLike | ResponseLike | FsReadStreamLike;
-
-/**
- * Intended to match DOM Blob, node-fetch Blob, node:buffer Blob, etc.
- * Don't add arrayBuffer here, node-fetch doesn't have it
- */
-interface BlobLike {
- /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Blob/size) */
- readonly size: number;
- /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Blob/type) */
- readonly type: string;
- /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Blob/text) */
- text(): Promise;
- /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Blob/slice) */
- slice(start?: number, end?: number): BlobLike;
-}
-
-/**
- * This check adds the arrayBuffer() method type because it is available and used at runtime
- */
-const isBlobLike = (value: any): value is BlobLike & { arrayBuffer(): Promise } =>
- value != null &&
- typeof value === 'object' &&
- typeof value.size === 'number' &&
- typeof value.type === 'string' &&
- typeof value.text === 'function' &&
- typeof value.slice === 'function' &&
- typeof value.arrayBuffer === 'function';
-
-/**
- * Intended to match DOM File, node:buffer File, undici File, etc.
- */
-interface FileLike extends BlobLike {
- /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/File/lastModified) */
- readonly lastModified: number;
- /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/File/name) */
- readonly name?: string | undefined;
-}
-declare var FileClass: {
- prototype: FileLike;
- new (fileBits: BlobPart[], fileName: string, options?: FilePropertyBag): FileLike;
-};
-
-/**
- * This check adds the arrayBuffer() method type because it is available and used at runtime
- */
-const isFileLike = (value: any): value is FileLike & { arrayBuffer(): Promise } =>
- value != null &&
- typeof value === 'object' &&
- typeof value.name === 'string' &&
- typeof value.lastModified === 'number' &&
- isBlobLike(value);
-
-/**
- * Intended to match DOM Response, node-fetch Response, undici Response, etc.
- */
-export interface ResponseLike {
- url: string;
- blob(): Promise;
-}
-
-const isResponseLike = (value: any): value is ResponseLike =>
- value != null &&
- typeof value === 'object' &&
- typeof value.url === 'string' &&
- typeof value.blob === 'function';
-
-const isUploadable = (value: any): value is Uploadable => {
- return isFileLike(value) || isResponseLike(value) || isFsReadStreamLike(value);
-};
-
-type ToFileInput = Uploadable | Exclude | AsyncIterable;
+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 and so that we don't
- * accidentally rely on a global `File` type in our annotations.
+ * for environments that don't define a global `File` yet.
*/
-function makeFile(fileBits: BlobPart[], fileName: string, options?: FilePropertyBag): FileLike {
- const File = (globalThis as any).File as typeof FileClass | undefined;
- if (typeof File === 'undefined') {
- throw new Error('`File` is not defined as a global which is required for file uploads');
- }
-
- return new File(fileBits, fileName, options);
-}
-
-/**
- * Helper for creating a {@link File} to pass to an SDK upload method from a variety of different data formats
- * @param value the raw content of the file. Can be an {@link Uploadable}, {@link BlobLikePart}, or {@link AsyncIterable} of {@link BlobLikePart}s
- * @param {string=} name the name of the file. If omitted, toFile will try to determine a file name from bits if possible
- * @param {Object=} options additional properties
- * @param {string=} options.type the MIME type of the content
- * @param {number=} options.lastModified the last modified timestamp
- * @returns a {@link File} with the given properties
- */
-export async function toFile(
- value: ToFileInput | PromiseLike,
- name?: string | null | undefined,
- options?: FilePropertyBag | undefined,
-): Promise {
- // If it's a promise, resolve it.
- value = await value;
-
- // If we've been given a `File` we don't need to do anything
- if (isFileLike(value)) {
- const File = (globalThis as any).File as typeof FileClass | undefined;
- if (File && value instanceof File) {
- return value;
- }
- return makeFile([await value.arrayBuffer()], value.name ?? 'unknown_file');
- }
-
- if (isResponseLike(value)) {
- const blob = await value.blob();
- name ||= new URL(value.url).pathname.split(/[\\/]/).pop() ?? 'unknown_file';
-
- return makeFile(await getBytes(blob), name, options);
- }
-
- const parts = await getBytes(value);
-
- name ||= getName(value) ?? 'unknown_file';
-
- 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);
+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 async function getBytes(
- value: Uploadable | BlobLikePart | AsyncIterable,
-): Promise> {
- let parts: Array = [];
- if (
- typeof value === 'string' ||
- ArrayBuffer.isView(value) || // includes Uint8Array, Buffer, etc.
- value instanceof ArrayBuffer
- ) {
- parts.push(value);
- } else if (isBlobLike(value)) {
- parts.push(value instanceof Blob ? value : await value.arrayBuffer());
- } else if (
- isAsyncIterableIterator(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(', ')}]`;
-}
-
-function getName(value: unknown): string | undefined {
+export function getName(value: any): string | undefined {
return (
- (typeof value === 'object' &&
- value !== null &&
- (('name' in value && String(value.name)) ||
- ('filename' in value && String(value.filename)) ||
- ('path' in value && String(value.path).split(/[\\/]/).pop()))) ||
- undefined
+ (
+ (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
);
}
-const isAsyncIterableIterator = (value: any): value is AsyncIterableIterator =>
+export const isAsyncIterable = (value: any): value is AsyncIterable =>
value != null && typeof value === 'object' && typeof value[Symbol.asyncIterator] === 'function';
/**
@@ -268,6 +123,16 @@ export const createForm = async >(
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);
@@ -290,9 +155,12 @@ const addFormValue = async (form: FormData, key: string, value: unknown): Promis
// TODO: make nested formats configurable
if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
form.append(key, String(value));
- } else if (isUploadable(value)) {
- const file = await toFile(value);
- form.append(key, file as any);
+ } 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') {
diff --git a/src/internal/utils/base64.ts b/src/internal/utils/base64.ts
index 3b077b3..04d8296 100644
--- a/src/internal/utils/base64.ts
+++ b/src/internal/utils/base64.ts
@@ -1,18 +1,19 @@
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-import { GitpodError } from '../../error';
+import { GitpodError } from '../../core/error';
+import { encodeUTF8 } from './bytes';
export const toBase64 = (data: string | Uint8Array | null | undefined): string => {
if (!data) return '';
- if (typeof data === 'string') {
- data = new (globalThis as any).TextEncoder().encode(data);
- }
-
if (typeof (globalThis as any).Buffer !== 'undefined') {
return (globalThis as any).Buffer.from(data).toString('base64');
}
+ if (typeof data === 'string') {
+ data = encodeUTF8(data);
+ }
+
if (typeof btoa !== 'undefined') {
return btoa(String.fromCharCode.apply(null, data as any));
}
@@ -22,15 +23,17 @@ export const toBase64 = (data: string | Uint8Array | null | undefined): string =
export const fromBase64 = (str: string): Uint8Array => {
if (typeof (globalThis as any).Buffer !== 'undefined') {
- return new Uint8Array((globalThis as any).Buffer.from(str, 'base64'));
+ const buf = (globalThis as any).Buffer.from(str, 'base64');
+ return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
}
if (typeof atob !== 'undefined') {
- return new Uint8Array(
- atob(str)
- .split('')
- .map((c) => c.charCodeAt(0)),
- );
+ 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/log.ts b/src/internal/utils/log.ts
index e446d4c..8fdf60d 100644
--- a/src/internal/utils/log.ts
+++ b/src/internal/utils/log.ts
@@ -1,9 +1,18 @@
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-import type { LogLevel, Logger } from '../../client';
+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,
@@ -12,6 +21,25 @@ const levelNumbers = {
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) {
diff --git a/src/internal/utils/path.ts b/src/internal/utils/path.ts
index 0115b07..56154a2 100644
--- a/src/internal/utils/path.ts
+++ b/src/internal/utils/path.ts
@@ -1,4 +1,4 @@
-import { GitpodError } from '../../error';
+import { GitpodError } from '../../core/error';
/**
* Percent-encode everything that isn't safe to have in a path without encoding safe chars.
diff --git a/src/internal/utils/uuid.ts b/src/internal/utils/uuid.ts
index 6c43f81..5a262c6 100644
--- a/src/internal/utils/uuid.ts
+++ b/src/internal/utils/uuid.ts
@@ -1,13 +1,19 @@
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-import { crypto } from '../polyfill/crypto.node';
+import { getCrypto } from '../shims/crypto';
/**
* https://stackoverflow.com/a/2117523
*/
-export function uuid4() {
- if (crypto.randomUUID) return crypto.randomUUID();
+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 ^ (crypto.getRandomValues(new Uint8Array(1))[0]! & (15 >> (+c / 4)))).toString(16),
+ (+c ^ (randomByte() & (15 >> (+c / 4)))).toString(16),
);
-}
+};
diff --git a/src/internal/utils/values.ts b/src/internal/utils/values.ts
index 86e3eda..d0e9c61 100644
--- a/src/internal/utils/values.ts
+++ b/src/internal/utils/values.ts
@@ -1,6 +1,6 @@
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
-import { GitpodError } from '../../error';
+import { GitpodError } from '../../core/error';
// https://url.spec.whatwg.org/#url-scheme-string
const startsWithSchemeRegexp = /^[a-z][a-z0-9+.-]*:/i;
@@ -92,3 +92,11 @@ export const maybeCoerceBoolean = (value: unknown): boolean | undefined => {
}
return coerceBoolean(value);
};
+
+export const safeJSON = (text: string) => {
+ try {
+ return JSON.parse(text);
+ } catch (err) {
+ return undefined;
+ }
+};
diff --git a/src/pagination.ts b/src/pagination.ts
index 7bacc0a..90bf015 100644
--- a/src/pagination.ts
+++ b/src/pagination.ts
@@ -1,1220 +1,2 @@
-// 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 { APIPromise } from './api-promise';
-import { type Gitpod } from './client';
-import { type APIResponseProps } from './internal/parse';
-import { maybeObj } from './internal/utils/values';
-
-export type PageRequestOptions = Pick;
-
-export abstract class AbstractPage