From 2f70ad9e95854605f9f38c401d49f8422d62af75 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 22 Feb 2025 08:52:42 +0000 Subject: [PATCH 01/26] fix(internal): return in castToError instead of throwing (#43) --- src/internal/errors.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 { From bd9e5361115c7f9adc8c8d9798f38a04b55ab03c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 22 Feb 2025 09:11:16 +0000 Subject: [PATCH 02/26] chore(internal): remove unnecessary todo (#45) --- src/internal/parse.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/internal/parse.ts b/src/internal/parse.ts index 799b71c..2085087 100644 --- a/src/internal/parse.ts +++ b/src/internal/parse.ts @@ -34,8 +34,6 @@ export async function defaultParseResponse<T>(client: Gitpod, props: APIResponse } const text = await response.text(); - - // TODO handle blob, arraybuffer, other content types, etc. return text as unknown as T; })(); loggerFor(client).debug( From 6450e47a5f12103274528a67028b91a01b9c55b8 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 28 Feb 2025 04:06:07 +0000 Subject: [PATCH 03/26] docs: update URLs from stainlessapi.com to stainless.com (#46) More details at https://www.stainless.com/changelog/stainless-com --- README.md | 2 +- SECURITY.md | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index e071c46..ae0223a 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 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 From cd888bc3c16d0d2cbf3b3c96ab23dc7d46360598 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 4 Mar 2025 10:33:40 +0000 Subject: [PATCH 04/26] chore(client): only accept standard types for file uploads (#47) --- scripts/build | 4 +- src/client.ts | 4 +- src/internal/polyfill/file.node.d.ts | 9 - src/internal/polyfill/file.node.js | 17 -- src/internal/polyfill/file.node.mjs | 9 - src/internal/shims.ts | 56 ----- .../{polyfill => shims}/crypto.node.d.ts | 0 .../{polyfill => shims}/crypto.node.js | 0 .../{polyfill => shims}/crypto.node.mjs | 0 src/internal/shims/file.node.d.ts | 20 ++ src/internal/shims/file.node.js | 11 + src/internal/shims/file.node.mjs | 2 + src/internal/to-file.ts | 152 ++++++++++++ src/internal/uploads.ts | 220 ++++-------------- src/internal/utils/uuid.ts | 2 +- src/uploads.ts | 3 +- tests/uploads.test.ts | 38 ++- 17 files changed, 267 insertions(+), 280 deletions(-) delete mode 100644 src/internal/polyfill/file.node.d.ts delete mode 100644 src/internal/polyfill/file.node.js delete mode 100644 src/internal/polyfill/file.node.mjs rename src/internal/{polyfill => shims}/crypto.node.d.ts (100%) rename src/internal/{polyfill => shims}/crypto.node.js (100%) rename src/internal/{polyfill => shims}/crypto.node.mjs (100%) create mode 100644 src/internal/shims/file.node.d.ts create mode 100644 src/internal/shims/file.node.js create mode 100644 src/internal/shims/file.node.mjs create mode 100644 src/internal/to-file.ts diff --git a/scripts/build b/scripts/build index 08bfe2e..7b100ad 100755 --- a/scripts/build +++ b/scripts/build @@ -40,8 +40,8 @@ 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 +mkdir -p dist/internal/shims +cp src/internal/shims/*.{mjs,js,d.ts} dist/internal/shims node scripts/utils/postprocess-files.cjs diff --git a/src/client.ts b/src/client.ts index 9836801..8c0af2b 100644 --- a/src/client.ts +++ b/src/client.ts @@ -726,7 +726,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, 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<any>; -} - -/** - * 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<typeof ReadableStream>; export function makeReadableStream(...args: ReadableStreamArgs): ReadableStream { diff --git a/src/internal/polyfill/crypto.node.d.ts b/src/internal/shims/crypto.node.d.ts similarity index 100% rename from src/internal/polyfill/crypto.node.d.ts rename to src/internal/shims/crypto.node.d.ts diff --git a/src/internal/polyfill/crypto.node.js b/src/internal/shims/crypto.node.js similarity index 100% rename from src/internal/polyfill/crypto.node.js rename to src/internal/shims/crypto.node.js diff --git a/src/internal/polyfill/crypto.node.mjs b/src/internal/shims/crypto.node.mjs similarity index 100% rename from src/internal/polyfill/crypto.node.mjs rename to src/internal/shims/crypto.node.mjs diff --git a/src/internal/shims/file.node.d.ts b/src/internal/shims/file.node.d.ts new file mode 100644 index 0000000..9dc6b2f --- /dev/null +++ b/src/internal/shims/file.node.d.ts @@ -0,0 +1,20 @@ +// The infer is to make TS show it as a nice union type, +// instead of literally `ConstructorParameters<typeof Blob>[0]` +type FallbackBlobSource = ConstructorParameters<typeof Blob>[0] extends infer T ? T : never; +/** + * A [`File`](https://developer.mozilla.org/en-US/docs/Web/API/File) provides information about files. + */ +declare class FallbackFile extends Blob { + constructor(sources: FallbackBlobSource, fileName: string, options?: any); + /** + * The name of the `File`. + */ + readonly name: string; + /** + * The last modified date of the `File`. + */ + readonly lastModified: number; +} +export type File = InstanceType<typeof File>; +export const File: typeof globalThis extends { File: infer fileConstructor } ? fileConstructor +: typeof FallbackFile; diff --git a/src/internal/shims/file.node.js b/src/internal/shims/file.node.js new file mode 100644 index 0000000..3f8c2ed --- /dev/null +++ b/src/internal/shims/file.node.js @@ -0,0 +1,11 @@ +if (typeof require !== 'undefined') { + if (globalThis.File) { + exports.File = globalThis.File; + } else { + try { + // Use [require][0](...) and not require(...) so bundlers don't try to bundle the + // buffer module. + exports.File = [require][0]('node:buffer').File; + } catch (e) {} + } +} diff --git a/src/internal/shims/file.node.mjs b/src/internal/shims/file.node.mjs new file mode 100644 index 0000000..1f103f5 --- /dev/null +++ b/src/internal/shims/file.node.mjs @@ -0,0 +1,2 @@ +import * as mod from './file.node.js'; +export const File = globalThis.File || mod.File; diff --git a/src/internal/to-file.ts b/src/internal/to-file.ts new file mode 100644 index 0000000..69b76d3 --- /dev/null +++ b/src/internal/to-file.ts @@ -0,0 +1,152 @@ +import { File } from './shims/file.node.js'; +import { BlobPart, getName, makeFile, isAsyncIterable } from './uploads'; +import type { FilePropertyBag } from './builtin-types'; + +type BlobLikePart = string | ArrayBuffer | ArrayBufferView | BlobLike | DataView; + +/** + * Intended to match DOM Blob, node-fetch Blob, node:buffer Blob, etc. + * Don't add arrayBuffer here, node-fetch doesn't have it + */ +interface BlobLike { + /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Blob/size) */ + readonly size: number; + /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Blob/type) */ + readonly type: string; + /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Blob/text) */ + text(): Promise<string>; + /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Blob/slice) */ + slice(start?: number, end?: number): BlobLike; +} + +/** + * This check adds the arrayBuffer() method type because it is available and used at runtime + */ +const isBlobLike = (value: any): value is BlobLike & { arrayBuffer(): Promise<ArrayBuffer> } => + value != null && + typeof value === 'object' && + typeof value.size === 'number' && + typeof value.type === 'string' && + typeof value.text === 'function' && + typeof value.slice === 'function' && + typeof value.arrayBuffer === 'function'; + +/** + * Intended to match DOM File, node:buffer File, undici File, etc. + */ +interface FileLike extends BlobLike { + /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/File/lastModified) */ + readonly lastModified: number; + /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/File/name) */ + readonly name?: string | undefined; +} + +/** + * This check adds the arrayBuffer() method type because it is available and used at runtime + */ +const isFileLike = (value: any): value is FileLike & { arrayBuffer(): Promise<ArrayBuffer> } => + value != null && + typeof value === 'object' && + typeof value.name === 'string' && + typeof value.lastModified === 'number' && + isBlobLike(value); + +/** + * Intended to match DOM Response, node-fetch Response, undici Response, etc. + */ +export interface ResponseLike { + url: string; + blob(): Promise<BlobLike>; +} + +const isResponseLike = (value: any): value is ResponseLike => + value != null && + typeof value === 'object' && + typeof value.url === 'string' && + typeof value.blob === 'function'; + +export type ToFileInput = + | FileLike + | ResponseLike + | Exclude<BlobLikePart, string> + | AsyncIterable<BlobLikePart>; + +/** + * Helper for creating a {@link File} to pass to an SDK upload method from a variety of different data formats + * @param value the raw content of the file. Can be an {@link Uploadable}, {@link BlobLikePart}, or {@link AsyncIterable} of {@link BlobLikePart}s + * @param {string=} name the name of the file. If omitted, toFile will try to determine a file name from bits if possible + * @param {Object=} options additional properties + * @param {string=} options.type the MIME type of the content + * @param {number=} options.lastModified the last modified timestamp + * @returns a {@link File} with the given properties + */ +export async function toFile( + value: ToFileInput | PromiseLike<ToFileInput>, + name?: string | null | undefined, + options?: FilePropertyBag | undefined, +): Promise<File> { + // If it's a promise, resolve it. + value = await value; + + // If we've been given a `File` we don't need to do anything + if (isFileLike(value)) { + if (File && value instanceof File) { + return value; + } + return makeFile([await value.arrayBuffer()], value.name); + } + + if (isResponseLike(value)) { + const blob = await value.blob(); + name ||= new URL(value.url).pathname.split(/[\\/]/).pop(); + + return makeFile(await getBytes(blob), name, options); + } + + const parts = await getBytes(value); + + name ||= getName(value); + + if (!options?.type) { + const type = parts.find((part) => typeof part === 'object' && 'type' in part && part.type); + if (typeof type === 'string') { + options = { ...options, type }; + } + } + + return makeFile(parts, name, options); +} + +async function getBytes(value: BlobLikePart | AsyncIterable<BlobLikePart>): Promise<Array<BlobPart>> { + let parts: Array<BlobPart> = []; + if ( + typeof value === 'string' || + ArrayBuffer.isView(value) || // includes Uint8Array, Buffer, etc. + value instanceof ArrayBuffer + ) { + parts.push(value); + } else if (isBlobLike(value)) { + parts.push(value instanceof Blob ? value : await value.arrayBuffer()); + } else if ( + isAsyncIterable(value) // includes Readable, ReadableStream, etc. + ) { + for await (const chunk of value) { + parts.push(...(await getBytes(chunk as BlobLikePart))); // TODO, consider validating? + } + } else { + const constructor = value?.constructor?.name; + throw new Error( + `Unexpected data type: ${typeof value}${ + constructor ? `; constructor: ${constructor}` : '' + }${propsForError(value)}`, + ); + } + + return parts; +} + +function propsForError(value: unknown): string { + if (typeof value !== 'object' || value === null) return ''; + const props = Object.getOwnPropertyNames(value); + return `; props: [${props.map((p) => `"${p}"`).join(', ')}]`; +} diff --git a/src/internal/uploads.ts b/src/internal/uploads.ts index ee2029c..54431c1 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 { File } from './shims/file.node.js'; +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<Uint8Array> & { path: string | { toString(): string } }; + +// https://github.com/oven-sh/bun/issues/5980 +interface BunFile extends Blob { + readonly name?: string | undefined; +} /** * Typically, this is a native "File" class. @@ -16,188 +21,41 @@ 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<string>; - /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/Blob/slice) */ - slice(start?: number, end?: number): BlobLike; -} - -/** - * This check adds the arrayBuffer() method type because it is available and used at runtime - */ -const isBlobLike = (value: any): value is BlobLike & { arrayBuffer(): Promise<ArrayBuffer> } => - value != null && - typeof value === 'object' && - typeof value.size === 'number' && - typeof value.type === 'string' && - typeof value.text === 'function' && - typeof value.slice === 'function' && - typeof value.arrayBuffer === 'function'; - -/** - * Intended to match DOM File, node:buffer File, undici File, etc. - */ -interface FileLike extends BlobLike { - /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/File/lastModified) */ - readonly lastModified: number; - /** [MDN Reference](https://developer.mozilla.org/docs/Web/API/File/name) */ - readonly name?: string | undefined; -} -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<ArrayBuffer> } => - value != null && - typeof value === 'object' && - typeof value.name === 'string' && - typeof value.lastModified === 'number' && - isBlobLike(value); - -/** - * Intended to match DOM Response, node-fetch Response, undici Response, etc. - */ -export interface ResponseLike { - url: string; - blob(): Promise<BlobLike>; -} - -const isResponseLike = (value: any): value is ResponseLike => - value != null && - typeof value === 'object' && - typeof value.url === 'string' && - typeof value.blob === 'function'; - -const isUploadable = (value: any): value is Uploadable => { - return isFileLike(value) || isResponseLike(value) || isFsReadStreamLike(value); -}; - -type ToFileInput = Uploadable | Exclude<BlobLikePart, string> | AsyncIterable<BlobLikePart>; +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; +export function makeFile( + fileBits: BlobPart[], + fileName: string | undefined, + options?: FilePropertyBag, +): File { 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); + return new File(fileBits as any, fileName ?? 'unknown_file', 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<ToFileInput>, - name?: string | null | undefined, - options?: FilePropertyBag | undefined, -): Promise<FileLike> { - // 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 async function getBytes( - value: Uploadable | BlobLikePart | AsyncIterable<BlobLikePart>, -): Promise<Array<BlobPart>> { - let parts: Array<BlobPart> = []; - if ( - typeof value === 'string' || - ArrayBuffer.isView(value) || // includes Uint8Array, Buffer, etc. - value instanceof ArrayBuffer - ) { - parts.push(value); - } else if (isBlobLike(value)) { - parts.push(value instanceof Blob ? value : await value.arrayBuffer()); - } else if ( - 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<unknown> => +export const isAsyncIterable = (value: any): value is AsyncIterable<any> => value != null && typeof value === 'object' && typeof value[Symbol.asyncIterator] === 'function'; /** @@ -268,6 +126,15 @@ export const createForm = async <T = Record<string, unknown>>( 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 File || (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 +157,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/uuid.ts b/src/internal/utils/uuid.ts index 6c43f81..1349c42 100644 --- a/src/internal/utils/uuid.ts +++ b/src/internal/utils/uuid.ts @@ -1,6 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { crypto } from '../polyfill/crypto.node'; +import { crypto } from '../shims/crypto.node.js'; /** * https://stackoverflow.com/a/2117523 diff --git a/src/uploads.ts b/src/uploads.ts index 77b6576..79d3073 100644 --- a/src/uploads.ts +++ b/src/uploads.ts @@ -1 +1,2 @@ -export { type Uploadable, toFile } from './internal/uploads'; +export { type Uploadable } from './internal/uploads'; +export { toFile, type ToFileInput } from './internal/to-file'; diff --git a/tests/uploads.test.ts b/tests/uploads.test.ts index 5758464..0fc3454 100644 --- a/tests/uploads.test.ts +++ b/tests/uploads.test.ts @@ -1,5 +1,5 @@ import fs from 'fs'; -import type { ResponseLike } from '@gitpod/sdk/internal/uploads'; +import type { ResponseLike } from '@gitpod/sdk/internal/to-file'; import { toFile } from '@gitpod/sdk/uploads'; class MyClass { @@ -13,6 +13,12 @@ function mockResponse({ url, content }: { url: string; content?: Blob }): Respon }; } +beforeEach(() => { + // The file shim captures the global File object when it's first imported. + // Reset modules before each test so we can test the error thrown when it's undefined. + jest.resetModules(); +}); + describe('toFile', () => { it('throws a helpful error for mismatched types', async () => { await expect( @@ -62,15 +68,29 @@ describe('toFile', () => { expect(file.name).toEqual('input.jsonl'); expect(file.type).toBe('jsonl'); }); + + it('is assignable to File and Blob', async () => { + const input = new File(['foo'], 'input.jsonl', { type: 'jsonl' }); + const result = await toFile(input); + const file: File = result; + const blob: Blob = result; + void file, blob; + }); }); -test('missing File error message', async () => { - // @ts-ignore - globalThis.File = undefined; +describe('missing File error message', () => { + beforeEach(() => { + // @ts-ignore + globalThis.File = undefined; + require('node:buffer').File = undefined; + }); - await expect( - toFile(mockResponse({ url: 'https://example.com/my/audio.mp3' })), - ).rejects.toMatchInlineSnapshot( - `[Error: \`File\` is not defined as a global which is required for file uploads]`, - ); + test('is thrown', async () => { + const uploads = await import('@gitpod/sdk/uploads'); + await expect( + uploads.toFile(mockResponse({ url: 'https://example.com/my/audio.mp3' })), + ).rejects.toMatchInlineSnapshot( + `[Error: \`File\` is not defined as a global which is required for file uploads]`, + ); + }); }); From c1031bd67090cc27d55472a5a32ee70df9ee781e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 4 Mar 2025 10:40:09 +0000 Subject: [PATCH 05/26] chore(internal): fix tests failing on node v18 (#48) --- tests/uploads.test.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/uploads.test.ts b/tests/uploads.test.ts index 0fc3454..a118892 100644 --- a/tests/uploads.test.ts +++ b/tests/uploads.test.ts @@ -1,6 +1,7 @@ import fs from 'fs'; import type { ResponseLike } from '@gitpod/sdk/internal/to-file'; import { toFile } from '@gitpod/sdk/uploads'; +import { File } from 'node:buffer'; class MyClass { name: string = 'foo'; From 41da630123709c225f8c173bbd2aace382d0e865 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 4 Mar 2025 10:41:57 +0000 Subject: [PATCH 06/26] chore(internal): constrain synckit dev dependency (#49) --- package.json | 3 +++ yarn.lock | 8 ++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index d59480b..dae603a 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,9 @@ "typescript": "^4.8.2", "typescript-eslint": "^8.24.0" }, + "resolutions": { + "synckit": "0.8.8" + }, "imports": { "@gitpod/sdk": ".", "@gitpod/sdk/*": "./src/*" diff --git a/yarn.lock b/yarn.lock index 6bd4ab2..6c01b49 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3317,10 +3317,10 @@ supports-preserve-symlinks-flag@^1.0.0: resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== -synckit@^0.9.1: - version "0.9.2" - resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.9.2.tgz#a3a935eca7922d48b9e7d6c61822ee6c3ae4ec62" - integrity sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw== +synckit@0.8.8, synckit@^0.9.1: + version "0.8.8" + resolved "https://registry.yarnpkg.com/synckit/-/synckit-0.8.8.tgz#fe7fe446518e3d3d49f5e429f443cf08b6edfcd7" + integrity sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ== dependencies: "@pkgr/core" "^0.1.0" tslib "^2.6.2" From 1262a7bcd5e0619e1eaef399ee967b629c79ce09 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 4 Mar 2025 10:44:15 +0000 Subject: [PATCH 07/26] fix(client): fix TypeError with undefined File (#50) --- src/internal/uploads.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/internal/uploads.ts b/src/internal/uploads.ts index 54431c1..e09bcbb 100644 --- a/src/internal/uploads.ts +++ b/src/internal/uploads.ts @@ -128,7 +128,8 @@ export const createForm = async <T = Record<string, unknown>>( // 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 File || (value instanceof Blob && 'name' in value); +const isNamedBlob = (value: object) => + (File && value instanceof File) || (value instanceof Blob && 'name' in value); const isUploadable = (value: unknown) => typeof value === 'object' && From e1e0fb509bfd526c9a8183480ad88330f0c7b240 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 4 Mar 2025 10:46:13 +0000 Subject: [PATCH 08/26] fix(internal): clean up undefined File test (#51) --- tests/uploads.test.ts | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/tests/uploads.test.ts b/tests/uploads.test.ts index a118892..f320eea 100644 --- a/tests/uploads.test.ts +++ b/tests/uploads.test.ts @@ -14,12 +14,6 @@ function mockResponse({ url, content }: { url: string; content?: Blob }): Respon }; } -beforeEach(() => { - // The file shim captures the global File object when it's first imported. - // Reset modules before each test so we can test the error thrown when it's undefined. - jest.resetModules(); -}); - describe('toFile', () => { it('throws a helpful error for mismatched types', async () => { await expect( @@ -80,11 +74,23 @@ describe('toFile', () => { }); describe('missing File error message', () => { + let prevFile: unknown; beforeEach(() => { + // The file shim captures the global File object when it's first imported. + // Reset modules before each test so we can test the error thrown when it's undefined. + jest.resetModules(); + // @ts-ignore + prevFile = globalThis.File; // @ts-ignore globalThis.File = undefined; require('node:buffer').File = undefined; }); + afterEach(() => { + // Clean up + // @ts-ignore + globalThis.File = prevFile; + jest.resetModules(); + }); test('is thrown', async () => { const uploads = await import('@gitpod/sdk/uploads'); From 2eded46344af89fbaef371ab685056b8952aa946 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 4 Mar 2025 10:47:26 +0000 Subject: [PATCH 09/26] fix(tests): manually reset node:buffer File (#52) --- tests/uploads.test.ts | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/tests/uploads.test.ts b/tests/uploads.test.ts index f320eea..7b28bb5 100644 --- a/tests/uploads.test.ts +++ b/tests/uploads.test.ts @@ -74,21 +74,25 @@ describe('toFile', () => { }); describe('missing File error message', () => { - let prevFile: unknown; + let prevGlobalFile: unknown; + let prevNodeFile: unknown; beforeEach(() => { // The file shim captures the global File object when it's first imported. // Reset modules before each test so we can test the error thrown when it's undefined. jest.resetModules(); + const buffer = require('node:buffer'); // @ts-ignore - prevFile = globalThis.File; + prevGlobalFile = globalThis.File; + prevNodeFile = buffer.File; // @ts-ignore globalThis.File = undefined; - require('node:buffer').File = undefined; + buffer.File = undefined; }); afterEach(() => { // Clean up // @ts-ignore - globalThis.File = prevFile; + globalThis.File = prevGlobalFile; + require('node:buffer').File = prevNodeFile; jest.resetModules(); }); From 54a7db864f182bd872aeceae04747930a3e419a7 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 5 Mar 2025 10:43:21 +0000 Subject: [PATCH 10/26] chore(types): improved go to definition on fetchOptions (#53) --- src/internal/types.ts | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/src/internal/types.ts b/src/internal/types.ts index 50c16e9..c3bce5a 100644 --- a/src/internal/types.ts +++ b/src/internal/types.ts @@ -6,14 +6,6 @@ export type HTTPMethod = 'get' | 'post' | 'put' | 'patch' | 'delete'; export type KeysEnum<T> = { [P in keyof Required<T>]: true }; type NotAny<T> = [unknown] extends [T] ? never : T; -type Literal<T> = PropertyKey extends T ? never : T; -type MappedLiteralKeys<T> = T extends any ? Literal<keyof T> : never; -type MappedIndex<T, K> = - T extends any ? - K extends keyof T ? - T[K] - : never - : never; /** * Some environments overload the global fetch function, and Parameters<T> only gets the last signature. @@ -93,6 +85,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<RequestInits>]?: MappedIndex<RequestInits, K> | undefined; -}; +export type MergedRequestInit = RequestInits & + /** We don't include these in the types as they'll be overridden for every request. */ + Partial<Record<'body' | 'headers' | 'method' | 'signal', never>>; From 25092c5070acc3602094bf34f304105cb7bd7157 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 5 Mar 2025 11:28:04 +0000 Subject: [PATCH 11/26] chore(docs): improve docs for withResponse/asResponse (#54) --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index ae0223a..0cbfd5f 100644 --- a/README.md +++ b/README.md @@ -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. <!-- prettier-ignore --> ```ts From 71a1bef58884eb34434a3e590cf0942c8166d33b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Tue, 11 Mar 2025 06:44:38 +0000 Subject: [PATCH 12/26] chore(internal): codegen related update (#55) --- scripts/bootstrap | 2 +- src/internal/parse.ts | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) 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/src/internal/parse.ts b/src/internal/parse.ts index 2085087..a12647d 100644 --- a/src/internal/parse.ts +++ b/src/internal/parse.ts @@ -26,8 +26,8 @@ export async function defaultParseResponse<T>(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; From 6431dc9927a315b9faf1e906c95930bcec65f3d5 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 14 Mar 2025 04:40:14 +0000 Subject: [PATCH 13/26] chore(internal): remove extra empty newlines (#56) --- .github/workflows/ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e3530dc..0312165 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -63,4 +63,3 @@ jobs: - name: Run tests run: ./scripts/test - From 23166e607ec2b8915a97e974e09cdc0abdbc6c23 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 14 Mar 2025 04:50:04 +0000 Subject: [PATCH 14/26] fix(exports): ensure resource imports don't require /index (#57) --- src/resources/environments.ts | 3 +++ src/resources/environments/automations.ts | 3 +++ src/resources/environments/automations/tasks.ts | 3 +++ src/resources/organizations.ts | 3 +++ src/resources/projects.ts | 3 +++ src/resources/runners.ts | 3 +++ src/resources/runners/configurations.ts | 3 +++ src/resources/users.ts | 3 +++ 8 files changed, 24 insertions(+) create mode 100644 src/resources/environments.ts create mode 100644 src/resources/environments/automations.ts create mode 100644 src/resources/environments/automations/tasks.ts create mode 100644 src/resources/organizations.ts create mode 100644 src/resources/projects.ts create mode 100644 src/resources/runners.ts create mode 100644 src/resources/runners/configurations.ts create mode 100644 src/resources/users.ts diff --git a/src/resources/environments.ts b/src/resources/environments.ts new file mode 100644 index 0000000..85fdba4 --- /dev/null +++ b/src/resources/environments.ts @@ -0,0 +1,3 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export * from './environments/index'; diff --git a/src/resources/environments/automations.ts b/src/resources/environments/automations.ts new file mode 100644 index 0000000..e13af42 --- /dev/null +++ b/src/resources/environments/automations.ts @@ -0,0 +1,3 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export * from './automations/index'; diff --git a/src/resources/environments/automations/tasks.ts b/src/resources/environments/automations/tasks.ts new file mode 100644 index 0000000..a93e814 --- /dev/null +++ b/src/resources/environments/automations/tasks.ts @@ -0,0 +1,3 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export * from './tasks/index'; diff --git a/src/resources/organizations.ts b/src/resources/organizations.ts new file mode 100644 index 0000000..61ddaf1 --- /dev/null +++ b/src/resources/organizations.ts @@ -0,0 +1,3 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export * from './organizations/index'; diff --git a/src/resources/projects.ts b/src/resources/projects.ts new file mode 100644 index 0000000..f9985fc --- /dev/null +++ b/src/resources/projects.ts @@ -0,0 +1,3 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export * from './projects/index'; diff --git a/src/resources/runners.ts b/src/resources/runners.ts new file mode 100644 index 0000000..003f18c --- /dev/null +++ b/src/resources/runners.ts @@ -0,0 +1,3 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export * from './runners/index'; diff --git a/src/resources/runners/configurations.ts b/src/resources/runners/configurations.ts new file mode 100644 index 0000000..451b34e --- /dev/null +++ b/src/resources/runners/configurations.ts @@ -0,0 +1,3 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export * from './configurations/index'; diff --git a/src/resources/users.ts b/src/resources/users.ts new file mode 100644 index 0000000..db908c7 --- /dev/null +++ b/src/resources/users.ts @@ -0,0 +1,3 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +export * from './users/index'; From 716b94c4be5a42cfaf9f59fcdb9332b912113869 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 15 Mar 2025 04:08:41 +0000 Subject: [PATCH 15/26] fix(internal): add mts file + crypto shim types (#58) --- scripts/build | 11 +++-------- src/internal/shims/crypto.node.d.mts | 1 + src/internal/shims/file.node.d.mts | 1 + 3 files changed, 5 insertions(+), 8 deletions(-) create mode 100644 src/internal/shims/crypto.node.d.mts create mode 100644 src/internal/shims/file.node.d.mts diff --git a/scripts/build b/scripts/build index 7b100ad..047fe3d 100755 --- a/scripts/build +++ b/scripts/build @@ -28,20 +28,15 @@ 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/shims -cp src/internal/shims/*.{mjs,js,d.ts} dist/internal/shims +cp src/internal/shims/*.{mjs,js,d.ts,d.mts} dist/internal/shims node scripts/utils/postprocess-files.cjs diff --git a/src/internal/shims/crypto.node.d.mts b/src/internal/shims/crypto.node.d.mts new file mode 100644 index 0000000..5cc1963 --- /dev/null +++ b/src/internal/shims/crypto.node.d.mts @@ -0,0 +1 @@ +export { crypto } from './crypto.node.js'; diff --git a/src/internal/shims/file.node.d.mts b/src/internal/shims/file.node.d.mts new file mode 100644 index 0000000..38cc9ff --- /dev/null +++ b/src/internal/shims/file.node.d.mts @@ -0,0 +1 @@ +export { File } from './file.node.js'; From 51d47fd93e6be04336019ec05c60841a5d25195c Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Wed, 19 Mar 2025 08:04:20 +0000 Subject: [PATCH 16/26] chore(internal): minor client file refactoring (#59) --- src/client.ts | 50 +++--------------------------------- src/internal/types.ts | 2 ++ src/internal/utils/log.ts | 30 +++++++++++++++++++++- src/internal/utils/values.ts | 8 ++++++ 4 files changed, 43 insertions(+), 47 deletions(-) diff --git a/src/client.ts b/src/client.ts index 8c0af2b..4371dfa 100644 --- a/src/client.ts +++ b/src/client.ts @@ -1,10 +1,12 @@ // 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'; @@ -235,48 +237,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<LogLevel, true> = { - 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 +310,6 @@ export interface ClientOptions { logger?: Logger | undefined; } -type FinalizedRequestInit = RequestInit & { headers: Headers }; - /** * API Client for interfacing with the Gitpod API. */ diff --git a/src/internal/types.ts b/src/internal/types.ts index c3bce5a..d7928cd 100644 --- a/src/internal/types.ts +++ b/src/internal/types.ts @@ -5,6 +5,8 @@ export type HTTPMethod = 'get' | 'post' | 'put' | 'patch' | 'delete'; export type KeysEnum<T> = { [P in keyof Required<T>]: true }; +export type FinalizedRequestInit = RequestInit & { headers: Headers }; + type NotAny<T> = [unknown] extends [T] ? never : T; /** 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/values.ts b/src/internal/utils/values.ts index 86e3eda..43b0e39 100644 --- a/src/internal/utils/values.ts +++ b/src/internal/utils/values.ts @@ -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; + } +}; From 0049aac07585fb4a1536ef6ff191b4ba5d5b9720 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 20 Mar 2025 04:51:04 +0000 Subject: [PATCH 17/26] chore(exports): cleaner resource index imports (#60) --- src/resources.ts | 1 + 1 file changed, 1 insertion(+) create mode 100644 src/resources.ts diff --git a/src/resources.ts b/src/resources.ts new file mode 100644 index 0000000..b283d57 --- /dev/null +++ b/src/resources.ts @@ -0,0 +1 @@ +export * from './resources/index'; From a9df2c166e44d19ff8b374e5225d29971c72bb3e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 20 Mar 2025 04:52:28 +0000 Subject: [PATCH 18/26] chore(exports): stop using path fallbacks (#61) --- scripts/utils/postprocess-files.cjs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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); From b79e1f2dd9348ab00466e4477af0fe08670354e4 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 27 Mar 2025 03:35:22 +0000 Subject: [PATCH 19/26] codegen metadata --- .stats.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.stats.yml b/.stats.yml index 2c4d8ac..e8f1d28 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 +openapi_spec_hash: 5dbb5577e6a7cae7db615b1b06c9d23e +config_hash: 719ad411c0ec7402a7a4c1f95515280c From e4008c3ab36557410e2124287eb9ab861e5d81d2 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 27 Mar 2025 03:42:03 +0000 Subject: [PATCH 20/26] chore(client): move misc public files to new `core/` directory, deprecate old paths (#62) --- src/api-promise.ts | 94 +- src/client.ts | 10 +- src/core/README.md | 3 + src/core/api-promise.ts | 92 ++ src/core/error.ts | 140 ++ src/core/pagination.ts | 1220 ++++++++++++++++ src/core/resource.ts | 11 + src/core/uploads.ts | 2 + src/error.ts | 142 +- src/index.ts | 8 +- src/internal/README.md | 3 + src/internal/decoders/jsonl.ts | 2 +- src/internal/decoders/line.ts | 2 +- src/internal/utils/base64.ts | 2 +- src/internal/utils/path.ts | 2 +- src/internal/utils/values.ts | 2 +- src/pagination.ts | 1222 +---------------- src/resource.ts | 13 +- src/resources/accounts.ts | 6 +- src/resources/editors.ts | 6 +- .../environments/automations/automations.ts | 4 +- .../environments/automations/services.ts | 6 +- .../automations/tasks/executions.ts | 6 +- .../environments/automations/tasks/tasks.ts | 6 +- src/resources/environments/classes.ts | 8 +- src/resources/environments/environments.ts | 6 +- src/resources/events.ts | 6 +- src/resources/groups.ts | 4 +- src/resources/identity.ts | 4 +- .../organizations/domain-verifications.ts | 10 +- src/resources/organizations/invites.ts | 4 +- src/resources/organizations/organizations.ts | 6 +- .../organizations/sso-configurations.ts | 6 +- src/resources/projects/policies.ts | 6 +- src/resources/projects/projects.ts | 6 +- .../runners/configurations/configurations.ts | 4 +- .../configurations/environment-classes.ts | 10 +- .../host-authentication-tokens.ts | 6 +- .../runners/configurations/schema.ts | 4 +- .../configurations/scm-integrations.ts | 6 +- src/resources/runners/policies.ts | 6 +- src/resources/runners/runners.ts | 6 +- src/resources/secrets.ts | 6 +- src/resources/shared.ts | 2 +- src/resources/users/pats.ts | 10 +- src/resources/users/users.ts | 4 +- src/uploads.ts | 4 +- tests/form.test.ts | 2 +- tests/index.test.ts | 2 +- tests/uploads.test.ts | 4 +- 50 files changed, 1589 insertions(+), 1557 deletions(-) create mode 100644 src/core/README.md create mode 100644 src/core/api-promise.ts create mode 100644 src/core/error.ts create mode 100644 src/core/pagination.ts create mode 100644 src/core/resource.ts create mode 100644 src/core/uploads.ts create mode 100644 src/internal/README.md 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<T> extends Promise<T> { - private parsedPromise: Promise<T> | undefined; - #client: Gitpod; - - constructor( - client: Gitpod, - private responsePromise: Promise<APIResponseProps>, - private parseResponse: ( - client: Gitpod, - props: APIResponseProps, - ) => PromiseOrValue<T> = defaultParseResponse, - ) { - super((resolve) => { - // this is maybe a bit weird but this has to be a no-op to not implicitly - // parse the response body; instead .then, .catch, .finally are overridden - // to parse the response - resolve(null as any); - }); - this.#client = client; - } - - _thenUnwrap<U>(transform: (data: T, props: APIResponseProps) => U): APIPromise<U> { - return new APIPromise(this.#client, this.responsePromise, async (client, props) => - transform(await this.parseResponse(client, props), props), - ); - } - - /** - * Gets the raw `Response` instance instead of parsing the response - * data. - * - * If you want to parse the response body but still get the `Response` - * instance, you can use {@link withResponse()}. - * - * 👋 Getting the wrong TypeScript type for `Response`? - * Try setting `"moduleResolution": "NodeNext"` or add `"lib": ["DOM"]` - * to your `tsconfig.json`. - */ - asResponse(): Promise<Response> { - return this.responsePromise.then((p) => p.response); - } - - /** - * Gets the parsed response data and the raw `Response` instance. - * - * If you just want to get the raw `Response` instance without parsing it, - * you can use {@link asResponse()}. - * - * 👋 Getting the wrong TypeScript type for `Response`? - * Try setting `"moduleResolution": "NodeNext"` or add `"lib": ["DOM"]` - * to your `tsconfig.json`. - */ - async withResponse(): Promise<{ data: T; response: Response }> { - const [data, response] = await Promise.all([this.parse(), this.asResponse()]); - return { data, response }; - } - - private parse(): Promise<T> { - if (!this.parsedPromise) { - this.parsedPromise = this.responsePromise.then((data) => this.parseResponse(this.#client, data)); - } - return this.parsedPromise; - } - - override then<TResult1 = T, TResult2 = never>( - onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null, - onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null, - ): Promise<TResult1 | TResult2> { - return this.parse().then(onfulfilled, onrejected); - } - - override catch<TResult = never>( - onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | undefined | null, - ): Promise<T | TResult> { - return this.parse().catch(onrejected); - } - - override finally(onfinally?: (() => void) | undefined | null): Promise<T> { - return this.parse().finally(onfinally); - } -} +/** @deprecated Import from ./core/api-promise instead */ +export * from './core/api-promise'; diff --git a/src/client.ts b/src/client.ts index 4371dfa..ef0b007 100644 --- a/src/client.ts +++ b/src/client.ts @@ -13,8 +13,8 @@ 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, @@ -57,10 +57,10 @@ import { 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'; diff --git a/src/core/README.md b/src/core/README.md new file mode 100644 index 0000000..485fce8 --- /dev/null +++ b/src/core/README.md @@ -0,0 +1,3 @@ +# `core` + +This directory holds public modules implementing non-resource-specific SDK functionality. diff --git a/src/core/api-promise.ts b/src/core/api-promise.ts new file mode 100644 index 0000000..639a545 --- /dev/null +++ b/src/core/api-promise.ts @@ -0,0 +1,92 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { type Gitpod } from '../client'; + +import { type PromiseOrValue } from '../internal/types'; +import { APIResponseProps, defaultParseResponse } from '../internal/parse'; + +/** + * A subclass of `Promise` providing additional helper methods + * for interacting with the SDK. + */ +export class APIPromise<T> extends Promise<T> { + private parsedPromise: Promise<T> | undefined; + #client: Gitpod; + + constructor( + client: Gitpod, + private responsePromise: Promise<APIResponseProps>, + private parseResponse: ( + client: Gitpod, + props: APIResponseProps, + ) => PromiseOrValue<T> = defaultParseResponse, + ) { + super((resolve) => { + // this is maybe a bit weird but this has to be a no-op to not implicitly + // parse the response body; instead .then, .catch, .finally are overridden + // to parse the response + resolve(null as any); + }); + this.#client = client; + } + + _thenUnwrap<U>(transform: (data: T, props: APIResponseProps) => U): APIPromise<U> { + return new APIPromise(this.#client, this.responsePromise, async (client, props) => + transform(await this.parseResponse(client, props), props), + ); + } + + /** + * Gets the raw `Response` instance instead of parsing the response + * data. + * + * If you want to parse the response body but still get the `Response` + * instance, you can use {@link withResponse()}. + * + * 👋 Getting the wrong TypeScript type for `Response`? + * Try setting `"moduleResolution": "NodeNext"` or add `"lib": ["DOM"]` + * to your `tsconfig.json`. + */ + asResponse(): Promise<Response> { + return this.responsePromise.then((p) => p.response); + } + + /** + * Gets the parsed response data and the raw `Response` instance. + * + * If you just want to get the raw `Response` instance without parsing it, + * you can use {@link asResponse()}. + * + * 👋 Getting the wrong TypeScript type for `Response`? + * Try setting `"moduleResolution": "NodeNext"` or add `"lib": ["DOM"]` + * to your `tsconfig.json`. + */ + async withResponse(): Promise<{ data: T; response: Response }> { + const [data, response] = await Promise.all([this.parse(), this.asResponse()]); + return { data, response }; + } + + private parse(): Promise<T> { + if (!this.parsedPromise) { + this.parsedPromise = this.responsePromise.then((data) => this.parseResponse(this.#client, data)); + } + return this.parsedPromise; + } + + override then<TResult1 = T, TResult2 = never>( + onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null, + onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null, + ): Promise<TResult1 | TResult2> { + return this.parse().then(onfulfilled, onrejected); + } + + override catch<TResult = never>( + onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | undefined | null, + ): Promise<T | TResult> { + return this.parse().catch(onrejected); + } + + override finally(onfinally?: (() => void) | undefined | null): Promise<T> { + return this.parse().finally(onfinally); + } +} diff --git a/src/core/error.ts b/src/core/error.ts new file mode 100644 index 0000000..1b22334 --- /dev/null +++ b/src/core/error.ts @@ -0,0 +1,140 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { castToError } from '../internal/errors'; +import * as Shared from '../resources/shared'; + +export class GitpodError extends Error {} + +export class APIError< + TStatus extends number | undefined = number | undefined, + THeaders extends Headers | undefined = Headers | undefined, + TError extends Object | undefined = Object | undefined, +> extends GitpodError { + /** HTTP status for the response that caused the error */ + readonly status: TStatus; + /** HTTP headers for the response that caused the error */ + readonly headers: THeaders; + /** JSON body of the response that caused the error */ + readonly error: TError; + + /** + * The status code, which should be an enum value of + * [google.rpc.Code][google.rpc.Code]. + */ + readonly code?: Shared.ErrorCode | undefined; + + constructor(status: TStatus, error: TError, message: string | undefined, headers: THeaders) { + super(`${APIError.makeMessage(status, error, message)}`); + this.status = status; + this.headers = headers; + this.error = error; + + const data = error as Record<string, any>; + this.code = data?.['code']; + } + + private static makeMessage(status: number | undefined, error: any, message: string | undefined) { + const msg = + error?.message ? + typeof error.message === 'string' ? + error.message + : JSON.stringify(error.message) + : error ? JSON.stringify(error) + : message; + + if (status && msg) { + return `${status} ${msg}`; + } + if (status) { + return `${status} status code (no body)`; + } + if (msg) { + return msg; + } + return '(no status code or body)'; + } + + static generate( + status: number | undefined, + errorResponse: Object | undefined, + message: string | undefined, + headers: Headers | undefined, + ): APIError { + if (!status || !headers) { + return new APIConnectionError({ message, cause: castToError(errorResponse) }); + } + + const error = errorResponse as Record<string, any>; + + if (status === 400) { + return new BadRequestError(status, error, message, headers); + } + + if (status === 401) { + return new AuthenticationError(status, error, message, headers); + } + + if (status === 403) { + return new PermissionDeniedError(status, error, message, headers); + } + + if (status === 404) { + return new NotFoundError(status, error, message, headers); + } + + if (status === 409) { + return new ConflictError(status, error, message, headers); + } + + if (status === 422) { + return new UnprocessableEntityError(status, error, message, headers); + } + + if (status === 429) { + return new RateLimitError(status, error, message, headers); + } + + if (status >= 500) { + return new InternalServerError(status, error, message, headers); + } + + return new APIError(status, error, message, headers); + } +} + +export class APIUserAbortError extends APIError<undefined, undefined, undefined> { + constructor({ message }: { message?: string } = {}) { + super(undefined, undefined, message || 'Request was aborted.', undefined); + } +} + +export class APIConnectionError extends APIError<undefined, undefined, undefined> { + constructor({ message, cause }: { message?: string | undefined; cause?: Error | undefined }) { + super(undefined, undefined, message || 'Connection error.', undefined); + // in some environments the 'cause' property is already declared + // @ts-ignore + if (cause) this.cause = cause; + } +} + +export class APIConnectionTimeoutError extends APIConnectionError { + constructor({ message }: { message?: string } = {}) { + super({ message: message ?? 'Request timed out.' }); + } +} + +export class BadRequestError extends APIError<400, Headers> {} + +export class AuthenticationError extends APIError<401, Headers> {} + +export class PermissionDeniedError extends APIError<403, Headers> {} + +export class NotFoundError extends APIError<404, Headers> {} + +export class ConflictError extends APIError<409, Headers> {} + +export class UnprocessableEntityError extends APIError<422, Headers> {} + +export class RateLimitError extends APIError<429, Headers> {} + +export class InternalServerError extends APIError<number, Headers> {} diff --git a/src/core/pagination.ts b/src/core/pagination.ts new file mode 100644 index 0000000..5ae7b97 --- /dev/null +++ b/src/core/pagination.ts @@ -0,0 +1,1220 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import { GitpodError } from './error'; +import { FinalRequestOptions } from '../internal/request-options'; +import { defaultParseResponse } from '../internal/parse'; +import { type Gitpod } from '../client'; +import { APIPromise } from './api-promise'; +import { type APIResponseProps } from '../internal/parse'; +import { maybeObj } from '../internal/utils/values'; + +export type PageRequestOptions = Pick<FinalRequestOptions, 'query' | 'headers' | 'body' | 'path' | 'method'>; + +export abstract class AbstractPage<Item> implements AsyncIterable<Item> { + #client: Gitpod; + protected options: FinalRequestOptions; + + protected response: Response; + protected body: unknown; + + constructor(client: Gitpod, response: Response, body: unknown, options: FinalRequestOptions) { + this.#client = client; + this.options = options; + this.response = response; + this.body = body; + } + + abstract nextPageRequestOptions(): PageRequestOptions | null; + + abstract getPaginatedItems(): Item[]; + + hasNextPage(): boolean { + const items = this.getPaginatedItems(); + if (!items.length) return false; + return this.nextPageRequestOptions() != null; + } + + async getNextPage(): Promise<this> { + const nextOptions = this.nextPageRequestOptions(); + if (!nextOptions) { + throw new GitpodError( + 'No next page expected; please check `.hasNextPage()` before calling `.getNextPage()`.', + ); + } + + return await this.#client.requestAPIList(this.constructor as any, nextOptions); + } + + async *iterPages(): AsyncGenerator<this> { + let page: this = this; + yield page; + while (page.hasNextPage()) { + page = await page.getNextPage(); + yield page; + } + } + + async *[Symbol.asyncIterator](): AsyncGenerator<Item> { + for await (const page of this.iterPages()) { + for (const item of page.getPaginatedItems()) { + yield item; + } + } + } +} + +/** + * This subclass of Promise will resolve to an instantiated Page once the request completes. + * + * It also implements AsyncIterable to allow auto-paginating iteration on an unawaited list call, eg: + * + * for await (const item of client.items.list()) { + * console.log(item) + * } + */ +export class PagePromise< + PageClass extends AbstractPage<Item>, + Item = ReturnType<PageClass['getPaginatedItems']>[number], + > + extends APIPromise<PageClass> + implements AsyncIterable<Item> +{ + constructor( + client: Gitpod, + request: Promise<APIResponseProps>, + Page: new (...args: ConstructorParameters<typeof AbstractPage>) => PageClass, + ) { + super( + client, + request, + async (client, props) => + new Page(client, props.response, await defaultParseResponse(client, props), props.options), + ); + } + + /** + * Allow auto-paginating iteration on an unawaited list call, eg: + * + * for await (const item of client.items.list()) { + * console.log(item) + * } + */ + async *[Symbol.asyncIterator]() { + const page = await this; + for await (const item of page) { + yield item; + } + } +} + +export interface DomainVerificationsPageResponse<Item> { + domainVerifications: Array<Item>; + + pagination: DomainVerificationsPageResponse.Pagination; +} + +export namespace DomainVerificationsPageResponse { + export interface Pagination { + nextToken?: string; + } +} + +export interface DomainVerificationsPageParams { + pageSize?: number; + + token?: string; +} + +export class DomainVerificationsPage<Item> + extends AbstractPage<Item> + implements DomainVerificationsPageResponse<Item> +{ + domainVerifications: Array<Item>; + + pagination: DomainVerificationsPageResponse.Pagination; + + constructor( + client: Gitpod, + response: Response, + body: DomainVerificationsPageResponse<Item>, + options: FinalRequestOptions, + ) { + super(client, response, body, options); + + this.domainVerifications = body.domainVerifications || []; + this.pagination = body.pagination || {}; + } + + getPaginatedItems(): Item[] { + return this.domainVerifications ?? []; + } + + nextPageRequestOptions(): PageRequestOptions | null { + const cursor = this.pagination?.nextToken; + if (!cursor) { + return null; + } + + return { + ...this.options, + query: { + ...maybeObj(this.options.query), + token: cursor, + }, + }; + } +} + +export interface EditorsPageResponse<Item> { + editors: Array<Item>; + + pagination: EditorsPageResponse.Pagination; +} + +export namespace EditorsPageResponse { + export interface Pagination { + nextToken?: string; + } +} + +export interface EditorsPageParams { + pageSize?: number; + + token?: string; +} + +export class EditorsPage<Item> extends AbstractPage<Item> implements EditorsPageResponse<Item> { + editors: Array<Item>; + + pagination: EditorsPageResponse.Pagination; + + constructor( + client: Gitpod, + response: Response, + body: EditorsPageResponse<Item>, + options: FinalRequestOptions, + ) { + super(client, response, body, options); + + this.editors = body.editors || []; + this.pagination = body.pagination || {}; + } + + getPaginatedItems(): Item[] { + return this.editors ?? []; + } + + nextPageRequestOptions(): PageRequestOptions | null { + const cursor = this.pagination?.nextToken; + if (!cursor) { + return null; + } + + return { + ...this.options, + query: { + ...maybeObj(this.options.query), + token: cursor, + }, + }; + } +} + +export interface EntriesPageResponse<Item> { + entries: Array<Item>; + + pagination: EntriesPageResponse.Pagination; +} + +export namespace EntriesPageResponse { + export interface Pagination { + nextToken?: string; + } +} + +export interface EntriesPageParams { + pageSize?: number; + + token?: string; +} + +export class EntriesPage<Item> extends AbstractPage<Item> implements EntriesPageResponse<Item> { + entries: Array<Item>; + + pagination: EntriesPageResponse.Pagination; + + constructor( + client: Gitpod, + response: Response, + body: EntriesPageResponse<Item>, + options: FinalRequestOptions, + ) { + super(client, response, body, options); + + this.entries = body.entries || []; + this.pagination = body.pagination || {}; + } + + getPaginatedItems(): Item[] { + return this.entries ?? []; + } + + nextPageRequestOptions(): PageRequestOptions | null { + const cursor = this.pagination?.nextToken; + if (!cursor) { + return null; + } + + return { + ...this.options, + query: { + ...maybeObj(this.options.query), + token: cursor, + }, + }; + } +} + +export interface EnvironmentClassesPageResponse<Item> { + environmentClasses: Array<Item>; + + pagination: EnvironmentClassesPageResponse.Pagination; +} + +export namespace EnvironmentClassesPageResponse { + export interface Pagination { + nextToken?: string; + } +} + +export interface EnvironmentClassesPageParams { + pageSize?: number; + + token?: string; +} + +export class EnvironmentClassesPage<Item> + extends AbstractPage<Item> + implements EnvironmentClassesPageResponse<Item> +{ + environmentClasses: Array<Item>; + + pagination: EnvironmentClassesPageResponse.Pagination; + + constructor( + client: Gitpod, + response: Response, + body: EnvironmentClassesPageResponse<Item>, + options: FinalRequestOptions, + ) { + super(client, response, body, options); + + this.environmentClasses = body.environmentClasses || []; + this.pagination = body.pagination || {}; + } + + getPaginatedItems(): Item[] { + return this.environmentClasses ?? []; + } + + nextPageRequestOptions(): PageRequestOptions | null { + const cursor = this.pagination?.nextToken; + if (!cursor) { + return null; + } + + return { + ...this.options, + query: { + ...maybeObj(this.options.query), + token: cursor, + }, + }; + } +} + +export interface EnvironmentsPageResponse<Item> { + environments: Array<Item>; + + pagination: EnvironmentsPageResponse.Pagination; +} + +export namespace EnvironmentsPageResponse { + export interface Pagination { + nextToken?: string; + } +} + +export interface EnvironmentsPageParams { + pageSize?: number; + + token?: string; +} + +export class EnvironmentsPage<Item> extends AbstractPage<Item> implements EnvironmentsPageResponse<Item> { + environments: Array<Item>; + + pagination: EnvironmentsPageResponse.Pagination; + + constructor( + client: Gitpod, + response: Response, + body: EnvironmentsPageResponse<Item>, + options: FinalRequestOptions, + ) { + super(client, response, body, options); + + this.environments = body.environments || []; + this.pagination = body.pagination || {}; + } + + getPaginatedItems(): Item[] { + return this.environments ?? []; + } + + nextPageRequestOptions(): PageRequestOptions | null { + const cursor = this.pagination?.nextToken; + if (!cursor) { + return null; + } + + return { + ...this.options, + query: { + ...maybeObj(this.options.query), + token: cursor, + }, + }; + } +} + +export interface GroupsPageResponse<Item> { + groups: Array<Item>; + + pagination: GroupsPageResponse.Pagination; +} + +export namespace GroupsPageResponse { + export interface Pagination { + nextToken?: string; + } +} + +export interface GroupsPageParams { + pageSize?: number; + + token?: string; +} + +export class GroupsPage<Item> extends AbstractPage<Item> implements GroupsPageResponse<Item> { + groups: Array<Item>; + + pagination: GroupsPageResponse.Pagination; + + constructor( + client: Gitpod, + response: Response, + body: GroupsPageResponse<Item>, + options: FinalRequestOptions, + ) { + super(client, response, body, options); + + this.groups = body.groups || []; + this.pagination = body.pagination || {}; + } + + getPaginatedItems(): Item[] { + return this.groups ?? []; + } + + nextPageRequestOptions(): PageRequestOptions | null { + const cursor = this.pagination?.nextToken; + if (!cursor) { + return null; + } + + return { + ...this.options, + query: { + ...maybeObj(this.options.query), + token: cursor, + }, + }; + } +} + +export interface IntegrationsPageResponse<Item> { + integrations: Array<Item>; + + pagination: IntegrationsPageResponse.Pagination; +} + +export namespace IntegrationsPageResponse { + export interface Pagination { + nextToken?: string; + } +} + +export interface IntegrationsPageParams { + pageSize?: number; + + token?: string; +} + +export class IntegrationsPage<Item> extends AbstractPage<Item> implements IntegrationsPageResponse<Item> { + integrations: Array<Item>; + + pagination: IntegrationsPageResponse.Pagination; + + constructor( + client: Gitpod, + response: Response, + body: IntegrationsPageResponse<Item>, + options: FinalRequestOptions, + ) { + super(client, response, body, options); + + this.integrations = body.integrations || []; + this.pagination = body.pagination || {}; + } + + getPaginatedItems(): Item[] { + return this.integrations ?? []; + } + + nextPageRequestOptions(): PageRequestOptions | null { + const cursor = this.pagination?.nextToken; + if (!cursor) { + return null; + } + + return { + ...this.options, + query: { + ...maybeObj(this.options.query), + token: cursor, + }, + }; + } +} + +export interface LoginProvidersPageResponse<Item> { + loginProviders: Array<Item>; + + pagination: LoginProvidersPageResponse.Pagination; +} + +export namespace LoginProvidersPageResponse { + export interface Pagination { + nextToken?: string; + } +} + +export interface LoginProvidersPageParams { + pageSize?: number; + + token?: string; +} + +export class LoginProvidersPage<Item> extends AbstractPage<Item> implements LoginProvidersPageResponse<Item> { + loginProviders: Array<Item>; + + pagination: LoginProvidersPageResponse.Pagination; + + constructor( + client: Gitpod, + response: Response, + body: LoginProvidersPageResponse<Item>, + options: FinalRequestOptions, + ) { + super(client, response, body, options); + + this.loginProviders = body.loginProviders || []; + this.pagination = body.pagination || {}; + } + + getPaginatedItems(): Item[] { + return this.loginProviders ?? []; + } + + nextPageRequestOptions(): PageRequestOptions | null { + const cursor = this.pagination?.nextToken; + if (!cursor) { + return null; + } + + return { + ...this.options, + query: { + ...maybeObj(this.options.query), + token: cursor, + }, + }; + } +} + +export interface MembersPageResponse<Item> { + members: Array<Item>; + + pagination: MembersPageResponse.Pagination; +} + +export namespace MembersPageResponse { + export interface Pagination { + nextToken?: string; + } +} + +export interface MembersPageParams { + pageSize?: number; + + token?: string; +} + +export class MembersPage<Item> extends AbstractPage<Item> implements MembersPageResponse<Item> { + members: Array<Item>; + + pagination: MembersPageResponse.Pagination; + + constructor( + client: Gitpod, + response: Response, + body: MembersPageResponse<Item>, + options: FinalRequestOptions, + ) { + super(client, response, body, options); + + this.members = body.members || []; + this.pagination = body.pagination || {}; + } + + getPaginatedItems(): Item[] { + return this.members ?? []; + } + + nextPageRequestOptions(): PageRequestOptions | null { + const cursor = this.pagination?.nextToken; + if (!cursor) { + return null; + } + + return { + ...this.options, + query: { + ...maybeObj(this.options.query), + token: cursor, + }, + }; + } +} + +export interface OrganizationsPageResponse<Item> { + organizations: Array<Item>; + + pagination: OrganizationsPageResponse.Pagination; +} + +export namespace OrganizationsPageResponse { + export interface Pagination { + nextToken?: string; + } +} + +export interface OrganizationsPageParams { + pageSize?: number; + + token?: string; +} + +export class OrganizationsPage<Item> extends AbstractPage<Item> implements OrganizationsPageResponse<Item> { + organizations: Array<Item>; + + pagination: OrganizationsPageResponse.Pagination; + + constructor( + client: Gitpod, + response: Response, + body: OrganizationsPageResponse<Item>, + options: FinalRequestOptions, + ) { + super(client, response, body, options); + + this.organizations = body.organizations || []; + this.pagination = body.pagination || {}; + } + + getPaginatedItems(): Item[] { + return this.organizations ?? []; + } + + nextPageRequestOptions(): PageRequestOptions | null { + const cursor = this.pagination?.nextToken; + if (!cursor) { + return null; + } + + return { + ...this.options, + query: { + ...maybeObj(this.options.query), + token: cursor, + }, + }; + } +} + +export interface PersonalAccessTokensPageResponse<Item> { + pagination: PersonalAccessTokensPageResponse.Pagination; + + personalAccessTokens: Array<Item>; +} + +export namespace PersonalAccessTokensPageResponse { + export interface Pagination { + nextToken?: string; + } +} + +export interface PersonalAccessTokensPageParams { + pageSize?: number; + + token?: string; +} + +export class PersonalAccessTokensPage<Item> + extends AbstractPage<Item> + implements PersonalAccessTokensPageResponse<Item> +{ + pagination: PersonalAccessTokensPageResponse.Pagination; + + personalAccessTokens: Array<Item>; + + constructor( + client: Gitpod, + response: Response, + body: PersonalAccessTokensPageResponse<Item>, + options: FinalRequestOptions, + ) { + super(client, response, body, options); + + this.pagination = body.pagination || {}; + this.personalAccessTokens = body.personalAccessTokens || []; + } + + getPaginatedItems(): Item[] { + return this.personalAccessTokens ?? []; + } + + nextPageRequestOptions(): PageRequestOptions | null { + const cursor = this.pagination?.nextToken; + if (!cursor) { + return null; + } + + return { + ...this.options, + query: { + ...maybeObj(this.options.query), + token: cursor, + }, + }; + } +} + +export interface PoliciesPageResponse<Item> { + pagination: PoliciesPageResponse.Pagination; + + policies: Array<Item>; +} + +export namespace PoliciesPageResponse { + export interface Pagination { + nextToken?: string; + } +} + +export interface PoliciesPageParams { + pageSize?: number; + + token?: string; +} + +export class PoliciesPage<Item> extends AbstractPage<Item> implements PoliciesPageResponse<Item> { + pagination: PoliciesPageResponse.Pagination; + + policies: Array<Item>; + + constructor( + client: Gitpod, + response: Response, + body: PoliciesPageResponse<Item>, + options: FinalRequestOptions, + ) { + super(client, response, body, options); + + this.pagination = body.pagination || {}; + this.policies = body.policies || []; + } + + getPaginatedItems(): Item[] { + return this.policies ?? []; + } + + nextPageRequestOptions(): PageRequestOptions | null { + const cursor = this.pagination?.nextToken; + if (!cursor) { + return null; + } + + return { + ...this.options, + query: { + ...maybeObj(this.options.query), + token: cursor, + }, + }; + } +} + +export interface ProjectsPageResponse<Item> { + pagination: ProjectsPageResponse.Pagination; + + projects: Array<Item>; +} + +export namespace ProjectsPageResponse { + export interface Pagination { + nextToken?: string; + } +} + +export interface ProjectsPageParams { + pageSize?: number; + + token?: string; +} + +export class ProjectsPage<Item> extends AbstractPage<Item> implements ProjectsPageResponse<Item> { + pagination: ProjectsPageResponse.Pagination; + + projects: Array<Item>; + + constructor( + client: Gitpod, + response: Response, + body: ProjectsPageResponse<Item>, + options: FinalRequestOptions, + ) { + super(client, response, body, options); + + this.pagination = body.pagination || {}; + this.projects = body.projects || []; + } + + getPaginatedItems(): Item[] { + return this.projects ?? []; + } + + nextPageRequestOptions(): PageRequestOptions | null { + const cursor = this.pagination?.nextToken; + if (!cursor) { + return null; + } + + return { + ...this.options, + query: { + ...maybeObj(this.options.query), + token: cursor, + }, + }; + } +} + +export interface RunnersPageResponse<Item> { + pagination: RunnersPageResponse.Pagination; + + runners: Array<Item>; +} + +export namespace RunnersPageResponse { + export interface Pagination { + nextToken?: string; + } +} + +export interface RunnersPageParams { + pageSize?: number; + + token?: string; +} + +export class RunnersPage<Item> extends AbstractPage<Item> implements RunnersPageResponse<Item> { + pagination: RunnersPageResponse.Pagination; + + runners: Array<Item>; + + constructor( + client: Gitpod, + response: Response, + body: RunnersPageResponse<Item>, + options: FinalRequestOptions, + ) { + super(client, response, body, options); + + this.pagination = body.pagination || {}; + this.runners = body.runners || []; + } + + getPaginatedItems(): Item[] { + return this.runners ?? []; + } + + nextPageRequestOptions(): PageRequestOptions | null { + const cursor = this.pagination?.nextToken; + if (!cursor) { + return null; + } + + return { + ...this.options, + query: { + ...maybeObj(this.options.query), + token: cursor, + }, + }; + } +} + +export interface SecretsPageResponse<Item> { + pagination: SecretsPageResponse.Pagination; + + secrets: Array<Item>; +} + +export namespace SecretsPageResponse { + export interface Pagination { + nextToken?: string; + } +} + +export interface SecretsPageParams { + pageSize?: number; + + token?: string; +} + +export class SecretsPage<Item> extends AbstractPage<Item> implements SecretsPageResponse<Item> { + pagination: SecretsPageResponse.Pagination; + + secrets: Array<Item>; + + constructor( + client: Gitpod, + response: Response, + body: SecretsPageResponse<Item>, + options: FinalRequestOptions, + ) { + super(client, response, body, options); + + this.pagination = body.pagination || {}; + this.secrets = body.secrets || []; + } + + getPaginatedItems(): Item[] { + return this.secrets ?? []; + } + + nextPageRequestOptions(): PageRequestOptions | null { + const cursor = this.pagination?.nextToken; + if (!cursor) { + return null; + } + + return { + ...this.options, + query: { + ...maybeObj(this.options.query), + token: cursor, + }, + }; + } +} + +export interface ServicesPageResponse<Item> { + pagination: ServicesPageResponse.Pagination; + + services: Array<Item>; +} + +export namespace ServicesPageResponse { + export interface Pagination { + nextToken?: string; + } +} + +export interface ServicesPageParams { + pageSize?: number; + + token?: string; +} + +export class ServicesPage<Item> extends AbstractPage<Item> implements ServicesPageResponse<Item> { + pagination: ServicesPageResponse.Pagination; + + services: Array<Item>; + + constructor( + client: Gitpod, + response: Response, + body: ServicesPageResponse<Item>, + options: FinalRequestOptions, + ) { + super(client, response, body, options); + + this.pagination = body.pagination || {}; + this.services = body.services || []; + } + + getPaginatedItems(): Item[] { + return this.services ?? []; + } + + nextPageRequestOptions(): PageRequestOptions | null { + const cursor = this.pagination?.nextToken; + if (!cursor) { + return null; + } + + return { + ...this.options, + query: { + ...maybeObj(this.options.query), + token: cursor, + }, + }; + } +} + +export interface SSOConfigurationsPageResponse<Item> { + pagination: SSOConfigurationsPageResponse.Pagination; + + ssoConfigurations: Array<Item>; +} + +export namespace SSOConfigurationsPageResponse { + export interface Pagination { + nextToken?: string; + } +} + +export interface SSOConfigurationsPageParams { + pageSize?: number; + + token?: string; +} + +export class SSOConfigurationsPage<Item> + extends AbstractPage<Item> + implements SSOConfigurationsPageResponse<Item> +{ + pagination: SSOConfigurationsPageResponse.Pagination; + + ssoConfigurations: Array<Item>; + + constructor( + client: Gitpod, + response: Response, + body: SSOConfigurationsPageResponse<Item>, + options: FinalRequestOptions, + ) { + super(client, response, body, options); + + this.pagination = body.pagination || {}; + this.ssoConfigurations = body.ssoConfigurations || []; + } + + getPaginatedItems(): Item[] { + return this.ssoConfigurations ?? []; + } + + nextPageRequestOptions(): PageRequestOptions | null { + const cursor = this.pagination?.nextToken; + if (!cursor) { + return null; + } + + return { + ...this.options, + query: { + ...maybeObj(this.options.query), + token: cursor, + }, + }; + } +} + +export interface TaskExecutionsPageResponse<Item> { + pagination: TaskExecutionsPageResponse.Pagination; + + taskExecutions: Array<Item>; +} + +export namespace TaskExecutionsPageResponse { + export interface Pagination { + nextToken?: string; + } +} + +export interface TaskExecutionsPageParams { + pageSize?: number; + + token?: string; +} + +export class TaskExecutionsPage<Item> extends AbstractPage<Item> implements TaskExecutionsPageResponse<Item> { + pagination: TaskExecutionsPageResponse.Pagination; + + taskExecutions: Array<Item>; + + constructor( + client: Gitpod, + response: Response, + body: TaskExecutionsPageResponse<Item>, + options: FinalRequestOptions, + ) { + super(client, response, body, options); + + this.pagination = body.pagination || {}; + this.taskExecutions = body.taskExecutions || []; + } + + getPaginatedItems(): Item[] { + return this.taskExecutions ?? []; + } + + nextPageRequestOptions(): PageRequestOptions | null { + const cursor = this.pagination?.nextToken; + if (!cursor) { + return null; + } + + return { + ...this.options, + query: { + ...maybeObj(this.options.query), + token: cursor, + }, + }; + } +} + +export interface TasksPageResponse<Item> { + pagination: TasksPageResponse.Pagination; + + tasks: Array<Item>; +} + +export namespace TasksPageResponse { + export interface Pagination { + nextToken?: string; + } +} + +export interface TasksPageParams { + pageSize?: number; + + token?: string; +} + +export class TasksPage<Item> extends AbstractPage<Item> implements TasksPageResponse<Item> { + pagination: TasksPageResponse.Pagination; + + tasks: Array<Item>; + + constructor( + client: Gitpod, + response: Response, + body: TasksPageResponse<Item>, + options: FinalRequestOptions, + ) { + super(client, response, body, options); + + this.pagination = body.pagination || {}; + this.tasks = body.tasks || []; + } + + getPaginatedItems(): Item[] { + return this.tasks ?? []; + } + + nextPageRequestOptions(): PageRequestOptions | null { + const cursor = this.pagination?.nextToken; + if (!cursor) { + return null; + } + + return { + ...this.options, + query: { + ...maybeObj(this.options.query), + token: cursor, + }, + }; + } +} + +export interface TokensPageResponse<Item> { + pagination: TokensPageResponse.Pagination; + + tokens: Array<Item>; +} + +export namespace TokensPageResponse { + export interface Pagination { + nextToken?: string; + } +} + +export interface TokensPageParams { + pageSize?: number; + + token?: string; +} + +export class TokensPage<Item> extends AbstractPage<Item> implements TokensPageResponse<Item> { + pagination: TokensPageResponse.Pagination; + + tokens: Array<Item>; + + constructor( + client: Gitpod, + response: Response, + body: TokensPageResponse<Item>, + options: FinalRequestOptions, + ) { + super(client, response, body, options); + + this.pagination = body.pagination || {}; + this.tokens = body.tokens || []; + } + + getPaginatedItems(): Item[] { + return this.tokens ?? []; + } + + nextPageRequestOptions(): PageRequestOptions | null { + const cursor = this.pagination?.nextToken; + if (!cursor) { + return null; + } + + return { + ...this.options, + query: { + ...maybeObj(this.options.query), + token: cursor, + }, + }; + } +} diff --git a/src/core/resource.ts b/src/core/resource.ts new file mode 100644 index 0000000..c73b82d --- /dev/null +++ b/src/core/resource.ts @@ -0,0 +1,11 @@ +// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. + +import type { Gitpod } from '../client'; + +export class APIResource { + protected _client: Gitpod; + + constructor(client: Gitpod) { + this._client = client; + } +} diff --git a/src/core/uploads.ts b/src/core/uploads.ts new file mode 100644 index 0000000..2882ca6 --- /dev/null +++ b/src/core/uploads.ts @@ -0,0 +1,2 @@ +export { type Uploadable } from '../internal/uploads'; +export { toFile, type ToFileInput } from '../internal/to-file'; diff --git a/src/error.ts b/src/error.ts 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<string, any>; - this.code = data?.['code']; - } - - private static makeMessage(status: number | undefined, error: any, message: string | undefined) { - const msg = - error?.message ? - typeof error.message === 'string' ? - error.message - : JSON.stringify(error.message) - : error ? JSON.stringify(error) - : message; - - if (status && msg) { - return `${status} ${msg}`; - } - if (status) { - return `${status} status code (no body)`; - } - if (msg) { - return msg; - } - return '(no status code or body)'; - } - - static generate( - status: number | undefined, - errorResponse: Object | undefined, - message: string | undefined, - headers: Headers | undefined, - ): APIError { - if (!status || !headers) { - return new APIConnectionError({ message, cause: castToError(errorResponse) }); - } - - const error = errorResponse as Record<string, any>; - - if (status === 400) { - return new BadRequestError(status, error, message, headers); - } - - if (status === 401) { - return new AuthenticationError(status, error, message, headers); - } - - if (status === 403) { - return new PermissionDeniedError(status, error, message, headers); - } - - if (status === 404) { - return new NotFoundError(status, error, message, headers); - } - - if (status === 409) { - return new ConflictError(status, error, message, headers); - } - - if (status === 422) { - return new UnprocessableEntityError(status, error, message, headers); - } - - if (status === 429) { - return new RateLimitError(status, error, message, headers); - } - - if (status >= 500) { - return new InternalServerError(status, error, message, headers); - } - - return new APIError(status, error, message, headers); - } -} - -export class APIUserAbortError extends APIError<undefined, undefined, undefined> { - constructor({ message }: { message?: string } = {}) { - super(undefined, undefined, message || 'Request was aborted.', undefined); - } -} - -export class APIConnectionError extends APIError<undefined, undefined, undefined> { - constructor({ message, cause }: { message?: string | undefined; cause?: Error | undefined }) { - super(undefined, undefined, message || 'Connection error.', undefined); - // in some environments the 'cause' property is already declared - // @ts-ignore - if (cause) this.cause = cause; - } -} - -export class APIConnectionTimeoutError extends APIConnectionError { - constructor({ message }: { message?: string } = {}) { - super({ message: message ?? 'Request timed out.' }); - } -} - -export class BadRequestError extends APIError<400, Headers> {} - -export class AuthenticationError extends APIError<401, Headers> {} - -export class PermissionDeniedError extends APIError<403, Headers> {} - -export class NotFoundError extends APIError<404, Headers> {} - -export class ConflictError extends APIError<409, Headers> {} - -export class UnprocessableEntityError extends APIError<422, Headers> {} - -export class RateLimitError extends APIError<429, Headers> {} - -export class InternalServerError extends APIError<number, Headers> {} +/** @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/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..a4c237f 100644 --- a/src/internal/decoders/line.ts +++ b/src/internal/decoders/line.ts @@ -1,4 +1,4 @@ -import { GitpodError } from '../../error'; +import { GitpodError } from '../../core/error'; export type Bytes = string | ArrayBuffer | Uint8Array | null | undefined; diff --git a/src/internal/utils/base64.ts b/src/internal/utils/base64.ts index 3b077b3..50d616c 100644 --- a/src/internal/utils/base64.ts +++ b/src/internal/utils/base64.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'; export const toBase64 = (data: string | Uint8Array | null | undefined): string => { if (!data) return ''; 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/values.ts b/src/internal/utils/values.ts index 43b0e39..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; 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<FinalRequestOptions, 'query' | 'headers' | 'body' | 'path' | 'method'>; - -export abstract class AbstractPage<Item> implements AsyncIterable<Item> { - #client: Gitpod; - protected options: FinalRequestOptions; - - protected response: Response; - protected body: unknown; - - constructor(client: Gitpod, response: Response, body: unknown, options: FinalRequestOptions) { - this.#client = client; - this.options = options; - this.response = response; - this.body = body; - } - - abstract nextPageRequestOptions(): PageRequestOptions | null; - - abstract getPaginatedItems(): Item[]; - - hasNextPage(): boolean { - const items = this.getPaginatedItems(); - if (!items.length) return false; - return this.nextPageRequestOptions() != null; - } - - async getNextPage(): Promise<this> { - const nextOptions = this.nextPageRequestOptions(); - if (!nextOptions) { - throw new GitpodError( - 'No next page expected; please check `.hasNextPage()` before calling `.getNextPage()`.', - ); - } - - return await this.#client.requestAPIList(this.constructor as any, nextOptions); - } - - async *iterPages(): AsyncGenerator<this> { - let page: this = this; - yield page; - while (page.hasNextPage()) { - page = await page.getNextPage(); - yield page; - } - } - - async *[Symbol.asyncIterator](): AsyncGenerator<Item> { - for await (const page of this.iterPages()) { - for (const item of page.getPaginatedItems()) { - yield item; - } - } - } -} - -/** - * This subclass of Promise will resolve to an instantiated Page once the request completes. - * - * It also implements AsyncIterable to allow auto-paginating iteration on an unawaited list call, eg: - * - * for await (const item of client.items.list()) { - * console.log(item) - * } - */ -export class PagePromise< - PageClass extends AbstractPage<Item>, - Item = ReturnType<PageClass['getPaginatedItems']>[number], - > - extends APIPromise<PageClass> - implements AsyncIterable<Item> -{ - constructor( - client: Gitpod, - request: Promise<APIResponseProps>, - Page: new (...args: ConstructorParameters<typeof AbstractPage>) => PageClass, - ) { - super( - client, - request, - async (client, props) => - new Page(client, props.response, await defaultParseResponse(client, props), props.options), - ); - } - - /** - * Allow auto-paginating iteration on an unawaited list call, eg: - * - * for await (const item of client.items.list()) { - * console.log(item) - * } - */ - async *[Symbol.asyncIterator]() { - const page = await this; - for await (const item of page) { - yield item; - } - } -} - -export interface DomainVerificationsPageResponse<Item> { - domainVerifications: Array<Item>; - - pagination: DomainVerificationsPageResponse.Pagination; -} - -export namespace DomainVerificationsPageResponse { - export interface Pagination { - nextToken?: string; - } -} - -export interface DomainVerificationsPageParams { - pageSize?: number; - - token?: string; -} - -export class DomainVerificationsPage<Item> - extends AbstractPage<Item> - implements DomainVerificationsPageResponse<Item> -{ - domainVerifications: Array<Item>; - - pagination: DomainVerificationsPageResponse.Pagination; - - constructor( - client: Gitpod, - response: Response, - body: DomainVerificationsPageResponse<Item>, - options: FinalRequestOptions, - ) { - super(client, response, body, options); - - this.domainVerifications = body.domainVerifications || []; - this.pagination = body.pagination || {}; - } - - getPaginatedItems(): Item[] { - return this.domainVerifications ?? []; - } - - nextPageRequestOptions(): PageRequestOptions | null { - const cursor = this.pagination?.nextToken; - if (!cursor) { - return null; - } - - return { - ...this.options, - query: { - ...maybeObj(this.options.query), - token: cursor, - }, - }; - } -} - -export interface EditorsPageResponse<Item> { - editors: Array<Item>; - - pagination: EditorsPageResponse.Pagination; -} - -export namespace EditorsPageResponse { - export interface Pagination { - nextToken?: string; - } -} - -export interface EditorsPageParams { - pageSize?: number; - - token?: string; -} - -export class EditorsPage<Item> extends AbstractPage<Item> implements EditorsPageResponse<Item> { - editors: Array<Item>; - - pagination: EditorsPageResponse.Pagination; - - constructor( - client: Gitpod, - response: Response, - body: EditorsPageResponse<Item>, - options: FinalRequestOptions, - ) { - super(client, response, body, options); - - this.editors = body.editors || []; - this.pagination = body.pagination || {}; - } - - getPaginatedItems(): Item[] { - return this.editors ?? []; - } - - nextPageRequestOptions(): PageRequestOptions | null { - const cursor = this.pagination?.nextToken; - if (!cursor) { - return null; - } - - return { - ...this.options, - query: { - ...maybeObj(this.options.query), - token: cursor, - }, - }; - } -} - -export interface EntriesPageResponse<Item> { - entries: Array<Item>; - - pagination: EntriesPageResponse.Pagination; -} - -export namespace EntriesPageResponse { - export interface Pagination { - nextToken?: string; - } -} - -export interface EntriesPageParams { - pageSize?: number; - - token?: string; -} - -export class EntriesPage<Item> extends AbstractPage<Item> implements EntriesPageResponse<Item> { - entries: Array<Item>; - - pagination: EntriesPageResponse.Pagination; - - constructor( - client: Gitpod, - response: Response, - body: EntriesPageResponse<Item>, - options: FinalRequestOptions, - ) { - super(client, response, body, options); - - this.entries = body.entries || []; - this.pagination = body.pagination || {}; - } - - getPaginatedItems(): Item[] { - return this.entries ?? []; - } - - nextPageRequestOptions(): PageRequestOptions | null { - const cursor = this.pagination?.nextToken; - if (!cursor) { - return null; - } - - return { - ...this.options, - query: { - ...maybeObj(this.options.query), - token: cursor, - }, - }; - } -} - -export interface EnvironmentClassesPageResponse<Item> { - environmentClasses: Array<Item>; - - pagination: EnvironmentClassesPageResponse.Pagination; -} - -export namespace EnvironmentClassesPageResponse { - export interface Pagination { - nextToken?: string; - } -} - -export interface EnvironmentClassesPageParams { - pageSize?: number; - - token?: string; -} - -export class EnvironmentClassesPage<Item> - extends AbstractPage<Item> - implements EnvironmentClassesPageResponse<Item> -{ - environmentClasses: Array<Item>; - - pagination: EnvironmentClassesPageResponse.Pagination; - - constructor( - client: Gitpod, - response: Response, - body: EnvironmentClassesPageResponse<Item>, - options: FinalRequestOptions, - ) { - super(client, response, body, options); - - this.environmentClasses = body.environmentClasses || []; - this.pagination = body.pagination || {}; - } - - getPaginatedItems(): Item[] { - return this.environmentClasses ?? []; - } - - nextPageRequestOptions(): PageRequestOptions | null { - const cursor = this.pagination?.nextToken; - if (!cursor) { - return null; - } - - return { - ...this.options, - query: { - ...maybeObj(this.options.query), - token: cursor, - }, - }; - } -} - -export interface EnvironmentsPageResponse<Item> { - environments: Array<Item>; - - pagination: EnvironmentsPageResponse.Pagination; -} - -export namespace EnvironmentsPageResponse { - export interface Pagination { - nextToken?: string; - } -} - -export interface EnvironmentsPageParams { - pageSize?: number; - - token?: string; -} - -export class EnvironmentsPage<Item> extends AbstractPage<Item> implements EnvironmentsPageResponse<Item> { - environments: Array<Item>; - - pagination: EnvironmentsPageResponse.Pagination; - - constructor( - client: Gitpod, - response: Response, - body: EnvironmentsPageResponse<Item>, - options: FinalRequestOptions, - ) { - super(client, response, body, options); - - this.environments = body.environments || []; - this.pagination = body.pagination || {}; - } - - getPaginatedItems(): Item[] { - return this.environments ?? []; - } - - nextPageRequestOptions(): PageRequestOptions | null { - const cursor = this.pagination?.nextToken; - if (!cursor) { - return null; - } - - return { - ...this.options, - query: { - ...maybeObj(this.options.query), - token: cursor, - }, - }; - } -} - -export interface GroupsPageResponse<Item> { - groups: Array<Item>; - - pagination: GroupsPageResponse.Pagination; -} - -export namespace GroupsPageResponse { - export interface Pagination { - nextToken?: string; - } -} - -export interface GroupsPageParams { - pageSize?: number; - - token?: string; -} - -export class GroupsPage<Item> extends AbstractPage<Item> implements GroupsPageResponse<Item> { - groups: Array<Item>; - - pagination: GroupsPageResponse.Pagination; - - constructor( - client: Gitpod, - response: Response, - body: GroupsPageResponse<Item>, - options: FinalRequestOptions, - ) { - super(client, response, body, options); - - this.groups = body.groups || []; - this.pagination = body.pagination || {}; - } - - getPaginatedItems(): Item[] { - return this.groups ?? []; - } - - nextPageRequestOptions(): PageRequestOptions | null { - const cursor = this.pagination?.nextToken; - if (!cursor) { - return null; - } - - return { - ...this.options, - query: { - ...maybeObj(this.options.query), - token: cursor, - }, - }; - } -} - -export interface IntegrationsPageResponse<Item> { - integrations: Array<Item>; - - pagination: IntegrationsPageResponse.Pagination; -} - -export namespace IntegrationsPageResponse { - export interface Pagination { - nextToken?: string; - } -} - -export interface IntegrationsPageParams { - pageSize?: number; - - token?: string; -} - -export class IntegrationsPage<Item> extends AbstractPage<Item> implements IntegrationsPageResponse<Item> { - integrations: Array<Item>; - - pagination: IntegrationsPageResponse.Pagination; - - constructor( - client: Gitpod, - response: Response, - body: IntegrationsPageResponse<Item>, - options: FinalRequestOptions, - ) { - super(client, response, body, options); - - this.integrations = body.integrations || []; - this.pagination = body.pagination || {}; - } - - getPaginatedItems(): Item[] { - return this.integrations ?? []; - } - - nextPageRequestOptions(): PageRequestOptions | null { - const cursor = this.pagination?.nextToken; - if (!cursor) { - return null; - } - - return { - ...this.options, - query: { - ...maybeObj(this.options.query), - token: cursor, - }, - }; - } -} - -export interface LoginProvidersPageResponse<Item> { - loginProviders: Array<Item>; - - pagination: LoginProvidersPageResponse.Pagination; -} - -export namespace LoginProvidersPageResponse { - export interface Pagination { - nextToken?: string; - } -} - -export interface LoginProvidersPageParams { - pageSize?: number; - - token?: string; -} - -export class LoginProvidersPage<Item> extends AbstractPage<Item> implements LoginProvidersPageResponse<Item> { - loginProviders: Array<Item>; - - pagination: LoginProvidersPageResponse.Pagination; - - constructor( - client: Gitpod, - response: Response, - body: LoginProvidersPageResponse<Item>, - options: FinalRequestOptions, - ) { - super(client, response, body, options); - - this.loginProviders = body.loginProviders || []; - this.pagination = body.pagination || {}; - } - - getPaginatedItems(): Item[] { - return this.loginProviders ?? []; - } - - nextPageRequestOptions(): PageRequestOptions | null { - const cursor = this.pagination?.nextToken; - if (!cursor) { - return null; - } - - return { - ...this.options, - query: { - ...maybeObj(this.options.query), - token: cursor, - }, - }; - } -} - -export interface MembersPageResponse<Item> { - members: Array<Item>; - - pagination: MembersPageResponse.Pagination; -} - -export namespace MembersPageResponse { - export interface Pagination { - nextToken?: string; - } -} - -export interface MembersPageParams { - pageSize?: number; - - token?: string; -} - -export class MembersPage<Item> extends AbstractPage<Item> implements MembersPageResponse<Item> { - members: Array<Item>; - - pagination: MembersPageResponse.Pagination; - - constructor( - client: Gitpod, - response: Response, - body: MembersPageResponse<Item>, - options: FinalRequestOptions, - ) { - super(client, response, body, options); - - this.members = body.members || []; - this.pagination = body.pagination || {}; - } - - getPaginatedItems(): Item[] { - return this.members ?? []; - } - - nextPageRequestOptions(): PageRequestOptions | null { - const cursor = this.pagination?.nextToken; - if (!cursor) { - return null; - } - - return { - ...this.options, - query: { - ...maybeObj(this.options.query), - token: cursor, - }, - }; - } -} - -export interface OrganizationsPageResponse<Item> { - organizations: Array<Item>; - - pagination: OrganizationsPageResponse.Pagination; -} - -export namespace OrganizationsPageResponse { - export interface Pagination { - nextToken?: string; - } -} - -export interface OrganizationsPageParams { - pageSize?: number; - - token?: string; -} - -export class OrganizationsPage<Item> extends AbstractPage<Item> implements OrganizationsPageResponse<Item> { - organizations: Array<Item>; - - pagination: OrganizationsPageResponse.Pagination; - - constructor( - client: Gitpod, - response: Response, - body: OrganizationsPageResponse<Item>, - options: FinalRequestOptions, - ) { - super(client, response, body, options); - - this.organizations = body.organizations || []; - this.pagination = body.pagination || {}; - } - - getPaginatedItems(): Item[] { - return this.organizations ?? []; - } - - nextPageRequestOptions(): PageRequestOptions | null { - const cursor = this.pagination?.nextToken; - if (!cursor) { - return null; - } - - return { - ...this.options, - query: { - ...maybeObj(this.options.query), - token: cursor, - }, - }; - } -} - -export interface PersonalAccessTokensPageResponse<Item> { - pagination: PersonalAccessTokensPageResponse.Pagination; - - personalAccessTokens: Array<Item>; -} - -export namespace PersonalAccessTokensPageResponse { - export interface Pagination { - nextToken?: string; - } -} - -export interface PersonalAccessTokensPageParams { - pageSize?: number; - - token?: string; -} - -export class PersonalAccessTokensPage<Item> - extends AbstractPage<Item> - implements PersonalAccessTokensPageResponse<Item> -{ - pagination: PersonalAccessTokensPageResponse.Pagination; - - personalAccessTokens: Array<Item>; - - constructor( - client: Gitpod, - response: Response, - body: PersonalAccessTokensPageResponse<Item>, - options: FinalRequestOptions, - ) { - super(client, response, body, options); - - this.pagination = body.pagination || {}; - this.personalAccessTokens = body.personalAccessTokens || []; - } - - getPaginatedItems(): Item[] { - return this.personalAccessTokens ?? []; - } - - nextPageRequestOptions(): PageRequestOptions | null { - const cursor = this.pagination?.nextToken; - if (!cursor) { - return null; - } - - return { - ...this.options, - query: { - ...maybeObj(this.options.query), - token: cursor, - }, - }; - } -} - -export interface PoliciesPageResponse<Item> { - pagination: PoliciesPageResponse.Pagination; - - policies: Array<Item>; -} - -export namespace PoliciesPageResponse { - export interface Pagination { - nextToken?: string; - } -} - -export interface PoliciesPageParams { - pageSize?: number; - - token?: string; -} - -export class PoliciesPage<Item> extends AbstractPage<Item> implements PoliciesPageResponse<Item> { - pagination: PoliciesPageResponse.Pagination; - - policies: Array<Item>; - - constructor( - client: Gitpod, - response: Response, - body: PoliciesPageResponse<Item>, - options: FinalRequestOptions, - ) { - super(client, response, body, options); - - this.pagination = body.pagination || {}; - this.policies = body.policies || []; - } - - getPaginatedItems(): Item[] { - return this.policies ?? []; - } - - nextPageRequestOptions(): PageRequestOptions | null { - const cursor = this.pagination?.nextToken; - if (!cursor) { - return null; - } - - return { - ...this.options, - query: { - ...maybeObj(this.options.query), - token: cursor, - }, - }; - } -} - -export interface ProjectsPageResponse<Item> { - pagination: ProjectsPageResponse.Pagination; - - projects: Array<Item>; -} - -export namespace ProjectsPageResponse { - export interface Pagination { - nextToken?: string; - } -} - -export interface ProjectsPageParams { - pageSize?: number; - - token?: string; -} - -export class ProjectsPage<Item> extends AbstractPage<Item> implements ProjectsPageResponse<Item> { - pagination: ProjectsPageResponse.Pagination; - - projects: Array<Item>; - - constructor( - client: Gitpod, - response: Response, - body: ProjectsPageResponse<Item>, - options: FinalRequestOptions, - ) { - super(client, response, body, options); - - this.pagination = body.pagination || {}; - this.projects = body.projects || []; - } - - getPaginatedItems(): Item[] { - return this.projects ?? []; - } - - nextPageRequestOptions(): PageRequestOptions | null { - const cursor = this.pagination?.nextToken; - if (!cursor) { - return null; - } - - return { - ...this.options, - query: { - ...maybeObj(this.options.query), - token: cursor, - }, - }; - } -} - -export interface RunnersPageResponse<Item> { - pagination: RunnersPageResponse.Pagination; - - runners: Array<Item>; -} - -export namespace RunnersPageResponse { - export interface Pagination { - nextToken?: string; - } -} - -export interface RunnersPageParams { - pageSize?: number; - - token?: string; -} - -export class RunnersPage<Item> extends AbstractPage<Item> implements RunnersPageResponse<Item> { - pagination: RunnersPageResponse.Pagination; - - runners: Array<Item>; - - constructor( - client: Gitpod, - response: Response, - body: RunnersPageResponse<Item>, - options: FinalRequestOptions, - ) { - super(client, response, body, options); - - this.pagination = body.pagination || {}; - this.runners = body.runners || []; - } - - getPaginatedItems(): Item[] { - return this.runners ?? []; - } - - nextPageRequestOptions(): PageRequestOptions | null { - const cursor = this.pagination?.nextToken; - if (!cursor) { - return null; - } - - return { - ...this.options, - query: { - ...maybeObj(this.options.query), - token: cursor, - }, - }; - } -} - -export interface SecretsPageResponse<Item> { - pagination: SecretsPageResponse.Pagination; - - secrets: Array<Item>; -} - -export namespace SecretsPageResponse { - export interface Pagination { - nextToken?: string; - } -} - -export interface SecretsPageParams { - pageSize?: number; - - token?: string; -} - -export class SecretsPage<Item> extends AbstractPage<Item> implements SecretsPageResponse<Item> { - pagination: SecretsPageResponse.Pagination; - - secrets: Array<Item>; - - constructor( - client: Gitpod, - response: Response, - body: SecretsPageResponse<Item>, - options: FinalRequestOptions, - ) { - super(client, response, body, options); - - this.pagination = body.pagination || {}; - this.secrets = body.secrets || []; - } - - getPaginatedItems(): Item[] { - return this.secrets ?? []; - } - - nextPageRequestOptions(): PageRequestOptions | null { - const cursor = this.pagination?.nextToken; - if (!cursor) { - return null; - } - - return { - ...this.options, - query: { - ...maybeObj(this.options.query), - token: cursor, - }, - }; - } -} - -export interface ServicesPageResponse<Item> { - pagination: ServicesPageResponse.Pagination; - - services: Array<Item>; -} - -export namespace ServicesPageResponse { - export interface Pagination { - nextToken?: string; - } -} - -export interface ServicesPageParams { - pageSize?: number; - - token?: string; -} - -export class ServicesPage<Item> extends AbstractPage<Item> implements ServicesPageResponse<Item> { - pagination: ServicesPageResponse.Pagination; - - services: Array<Item>; - - constructor( - client: Gitpod, - response: Response, - body: ServicesPageResponse<Item>, - options: FinalRequestOptions, - ) { - super(client, response, body, options); - - this.pagination = body.pagination || {}; - this.services = body.services || []; - } - - getPaginatedItems(): Item[] { - return this.services ?? []; - } - - nextPageRequestOptions(): PageRequestOptions | null { - const cursor = this.pagination?.nextToken; - if (!cursor) { - return null; - } - - return { - ...this.options, - query: { - ...maybeObj(this.options.query), - token: cursor, - }, - }; - } -} - -export interface SSOConfigurationsPageResponse<Item> { - pagination: SSOConfigurationsPageResponse.Pagination; - - ssoConfigurations: Array<Item>; -} - -export namespace SSOConfigurationsPageResponse { - export interface Pagination { - nextToken?: string; - } -} - -export interface SSOConfigurationsPageParams { - pageSize?: number; - - token?: string; -} - -export class SSOConfigurationsPage<Item> - extends AbstractPage<Item> - implements SSOConfigurationsPageResponse<Item> -{ - pagination: SSOConfigurationsPageResponse.Pagination; - - ssoConfigurations: Array<Item>; - - constructor( - client: Gitpod, - response: Response, - body: SSOConfigurationsPageResponse<Item>, - options: FinalRequestOptions, - ) { - super(client, response, body, options); - - this.pagination = body.pagination || {}; - this.ssoConfigurations = body.ssoConfigurations || []; - } - - getPaginatedItems(): Item[] { - return this.ssoConfigurations ?? []; - } - - nextPageRequestOptions(): PageRequestOptions | null { - const cursor = this.pagination?.nextToken; - if (!cursor) { - return null; - } - - return { - ...this.options, - query: { - ...maybeObj(this.options.query), - token: cursor, - }, - }; - } -} - -export interface TaskExecutionsPageResponse<Item> { - pagination: TaskExecutionsPageResponse.Pagination; - - taskExecutions: Array<Item>; -} - -export namespace TaskExecutionsPageResponse { - export interface Pagination { - nextToken?: string; - } -} - -export interface TaskExecutionsPageParams { - pageSize?: number; - - token?: string; -} - -export class TaskExecutionsPage<Item> extends AbstractPage<Item> implements TaskExecutionsPageResponse<Item> { - pagination: TaskExecutionsPageResponse.Pagination; - - taskExecutions: Array<Item>; - - constructor( - client: Gitpod, - response: Response, - body: TaskExecutionsPageResponse<Item>, - options: FinalRequestOptions, - ) { - super(client, response, body, options); - - this.pagination = body.pagination || {}; - this.taskExecutions = body.taskExecutions || []; - } - - getPaginatedItems(): Item[] { - return this.taskExecutions ?? []; - } - - nextPageRequestOptions(): PageRequestOptions | null { - const cursor = this.pagination?.nextToken; - if (!cursor) { - return null; - } - - return { - ...this.options, - query: { - ...maybeObj(this.options.query), - token: cursor, - }, - }; - } -} - -export interface TasksPageResponse<Item> { - pagination: TasksPageResponse.Pagination; - - tasks: Array<Item>; -} - -export namespace TasksPageResponse { - export interface Pagination { - nextToken?: string; - } -} - -export interface TasksPageParams { - pageSize?: number; - - token?: string; -} - -export class TasksPage<Item> extends AbstractPage<Item> implements TasksPageResponse<Item> { - pagination: TasksPageResponse.Pagination; - - tasks: Array<Item>; - - constructor( - client: Gitpod, - response: Response, - body: TasksPageResponse<Item>, - options: FinalRequestOptions, - ) { - super(client, response, body, options); - - this.pagination = body.pagination || {}; - this.tasks = body.tasks || []; - } - - getPaginatedItems(): Item[] { - return this.tasks ?? []; - } - - nextPageRequestOptions(): PageRequestOptions | null { - const cursor = this.pagination?.nextToken; - if (!cursor) { - return null; - } - - return { - ...this.options, - query: { - ...maybeObj(this.options.query), - token: cursor, - }, - }; - } -} - -export interface TokensPageResponse<Item> { - pagination: TokensPageResponse.Pagination; - - tokens: Array<Item>; -} - -export namespace TokensPageResponse { - export interface Pagination { - nextToken?: string; - } -} - -export interface TokensPageParams { - pageSize?: number; - - token?: string; -} - -export class TokensPage<Item> extends AbstractPage<Item> implements TokensPageResponse<Item> { - pagination: TokensPageResponse.Pagination; - - tokens: Array<Item>; - - constructor( - client: Gitpod, - response: Response, - body: TokensPageResponse<Item>, - options: FinalRequestOptions, - ) { - super(client, response, body, options); - - this.pagination = body.pagination || {}; - this.tokens = body.tokens || []; - } - - getPaginatedItems(): Item[] { - return this.tokens ?? []; - } - - nextPageRequestOptions(): PageRequestOptions | null { - const cursor = this.pagination?.nextToken; - if (!cursor) { - return null; - } - - return { - ...this.options, - query: { - ...maybeObj(this.options.query), - token: cursor, - }, - }; - } -} +/** @deprecated Import from ./core/pagination instead */ +export * from './core/pagination'; diff --git a/src/resource.ts b/src/resource.ts index ce38897..363e351 100644 --- a/src/resource.ts +++ b/src/resource.ts @@ -1,11 +1,2 @@ -// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. - -import type { Gitpod } from './client'; - -export class APIResource { - protected _client: Gitpod; - - constructor(client: Gitpod) { - this._client = client; - } -} +/** @deprecated Import from ./core/resource instead */ +export * from './core/resource'; diff --git a/src/resources/accounts.ts b/src/resources/accounts.ts index 6704ddc..b341c47 100644 --- a/src/resources/accounts.ts +++ b/src/resources/accounts.ts @@ -1,9 +1,9 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { APIResource } from '../resource'; +import { APIResource } from '../core/resource'; import * as Shared from './shared'; -import { APIPromise } from '../api-promise'; -import { LoginProvidersPage, type LoginProvidersPageParams, PagePromise } from '../pagination'; +import { APIPromise } from '../core/api-promise'; +import { LoginProvidersPage, type LoginProvidersPageParams, PagePromise } from '../core/pagination'; import { RequestOptions } from '../internal/request-options'; export class Accounts extends APIResource { diff --git a/src/resources/editors.ts b/src/resources/editors.ts index 11232fc..28832f9 100644 --- a/src/resources/editors.ts +++ b/src/resources/editors.ts @@ -1,8 +1,8 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { APIResource } from '../resource'; -import { APIPromise } from '../api-promise'; -import { EditorsPage, type EditorsPageParams, PagePromise } from '../pagination'; +import { APIResource } from '../core/resource'; +import { APIPromise } from '../core/api-promise'; +import { EditorsPage, type EditorsPageParams, PagePromise } from '../core/pagination'; import { RequestOptions } from '../internal/request-options'; export class Editors extends APIResource { diff --git a/src/resources/environments/automations/automations.ts b/src/resources/environments/automations/automations.ts index 9659f33..a369c3c 100644 --- a/src/resources/environments/automations/automations.ts +++ b/src/resources/environments/automations/automations.ts @@ -1,6 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { APIResource } from '../../../resource'; +import { APIResource } from '../../../core/resource'; import * as Shared from '../../shared'; import * as ServicesAPI from './services'; import { @@ -40,7 +40,7 @@ import { TaskUpdateResponse, Tasks as TasksAPITasks, } from './tasks/tasks'; -import { APIPromise } from '../../../api-promise'; +import { APIPromise } from '../../../core/api-promise'; import { RequestOptions } from '../../../internal/request-options'; export class Automations extends APIResource { diff --git a/src/resources/environments/automations/services.ts b/src/resources/environments/automations/services.ts index 4089844..6941f18 100644 --- a/src/resources/environments/automations/services.ts +++ b/src/resources/environments/automations/services.ts @@ -1,10 +1,10 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { APIResource } from '../../../resource'; +import { APIResource } from '../../../core/resource'; import * as ServicesAPI from './services'; import * as Shared from '../../shared'; -import { APIPromise } from '../../../api-promise'; -import { PagePromise, ServicesPage, type ServicesPageParams } from '../../../pagination'; +import { APIPromise } from '../../../core/api-promise'; +import { PagePromise, ServicesPage, type ServicesPageParams } from '../../../core/pagination'; import { RequestOptions } from '../../../internal/request-options'; export class Services extends APIResource { diff --git a/src/resources/environments/automations/tasks/executions.ts b/src/resources/environments/automations/tasks/executions.ts index d8bc0cf..47410d8 100644 --- a/src/resources/environments/automations/tasks/executions.ts +++ b/src/resources/environments/automations/tasks/executions.ts @@ -1,10 +1,10 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { APIResource } from '../../../../resource'; +import { APIResource } from '../../../../core/resource'; import * as Shared from '../../../shared'; import { TaskExecutionsTaskExecutionsPage } from '../../../shared'; -import { APIPromise } from '../../../../api-promise'; -import { PagePromise, TaskExecutionsPage, type TaskExecutionsPageParams } from '../../../../pagination'; +import { APIPromise } from '../../../../core/api-promise'; +import { PagePromise, TaskExecutionsPage, type TaskExecutionsPageParams } from '../../../../core/pagination'; import { RequestOptions } from '../../../../internal/request-options'; export class Executions extends APIResource { diff --git a/src/resources/environments/automations/tasks/tasks.ts b/src/resources/environments/automations/tasks/tasks.ts index a1e1b97..6a85c1f 100644 --- a/src/resources/environments/automations/tasks/tasks.ts +++ b/src/resources/environments/automations/tasks/tasks.ts @@ -1,6 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { APIResource } from '../../../../resource'; +import { APIResource } from '../../../../core/resource'; import * as Shared from '../../../shared'; import { TasksTasksPage } from '../../../shared'; import * as ExecutionsAPI from './executions'; @@ -12,8 +12,8 @@ import { ExecutionStopResponse, Executions, } from './executions'; -import { APIPromise } from '../../../../api-promise'; -import { PagePromise, TasksPage, type TasksPageParams } from '../../../../pagination'; +import { APIPromise } from '../../../../core/api-promise'; +import { PagePromise, TasksPage, type TasksPageParams } from '../../../../core/pagination'; import { RequestOptions } from '../../../../internal/request-options'; export class Tasks extends APIResource { diff --git a/src/resources/environments/classes.ts b/src/resources/environments/classes.ts index d1a03ee..709e8bc 100644 --- a/src/resources/environments/classes.ts +++ b/src/resources/environments/classes.ts @@ -1,10 +1,14 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { APIResource } from '../../resource'; +import { APIResource } from '../../core/resource'; import * as Shared from '../shared'; import { EnvironmentClassesEnvironmentClassesPage } from '../shared'; import * as RunnersAPI from '../runners/runners'; -import { EnvironmentClassesPage, type EnvironmentClassesPageParams, PagePromise } from '../../pagination'; +import { + EnvironmentClassesPage, + type EnvironmentClassesPageParams, + PagePromise, +} from '../../core/pagination'; import { RequestOptions } from '../../internal/request-options'; export class Classes extends APIResource { diff --git a/src/resources/environments/environments.ts b/src/resources/environments/environments.ts index ee1390b..2534b7f 100644 --- a/src/resources/environments/environments.ts +++ b/src/resources/environments/environments.ts @@ -1,6 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { APIResource } from '../../resource'; +import { APIResource } from '../../core/resource'; import * as EnvironmentsAPI from './environments'; import * as Shared from '../shared'; import * as ClassesAPI from './classes'; @@ -14,8 +14,8 @@ import { Automations, AutomationsFile as AutomationsAPIAutomationsFile, } from './automations/automations'; -import { APIPromise } from '../../api-promise'; -import { EnvironmentsPage, type EnvironmentsPageParams, PagePromise } from '../../pagination'; +import { APIPromise } from '../../core/api-promise'; +import { EnvironmentsPage, type EnvironmentsPageParams, PagePromise } from '../../core/pagination'; import { RequestOptions } from '../../internal/request-options'; export class Environments extends APIResource { diff --git a/src/resources/events.ts b/src/resources/events.ts index 927e568..68a011a 100644 --- a/src/resources/events.ts +++ b/src/resources/events.ts @@ -1,10 +1,10 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { APIResource } from '../resource'; +import { APIResource } from '../core/resource'; import * as EventsAPI from './events'; import * as Shared from './shared'; -import { APIPromise } from '../api-promise'; -import { EntriesPage, type EntriesPageParams, PagePromise } from '../pagination'; +import { APIPromise } from '../core/api-promise'; +import { EntriesPage, type EntriesPageParams, PagePromise } from '../core/pagination'; import { buildHeaders } from '../internal/headers'; import { RequestOptions } from '../internal/request-options'; import { JSONLDecoder } from '../internal/decoders/jsonl'; diff --git a/src/resources/groups.ts b/src/resources/groups.ts index b67b15c..56384a4 100644 --- a/src/resources/groups.ts +++ b/src/resources/groups.ts @@ -1,7 +1,7 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { APIResource } from '../resource'; -import { GroupsPage, type GroupsPageParams, PagePromise } from '../pagination'; +import { APIResource } from '../core/resource'; +import { GroupsPage, type GroupsPageParams, PagePromise } from '../core/pagination'; import { RequestOptions } from '../internal/request-options'; export class Groups extends APIResource { diff --git a/src/resources/identity.ts b/src/resources/identity.ts index 9bfb3fd..e351965 100644 --- a/src/resources/identity.ts +++ b/src/resources/identity.ts @@ -1,8 +1,8 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { APIResource } from '../resource'; +import { APIResource } from '../core/resource'; import * as Shared from './shared'; -import { APIPromise } from '../api-promise'; +import { APIPromise } from '../core/api-promise'; import { RequestOptions } from '../internal/request-options'; export class Identity extends APIResource { diff --git a/src/resources/organizations/domain-verifications.ts b/src/resources/organizations/domain-verifications.ts index 8fcb6a9..51e3a9e 100644 --- a/src/resources/organizations/domain-verifications.ts +++ b/src/resources/organizations/domain-verifications.ts @@ -1,8 +1,12 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { APIResource } from '../../resource'; -import { APIPromise } from '../../api-promise'; -import { DomainVerificationsPage, type DomainVerificationsPageParams, PagePromise } from '../../pagination'; +import { APIResource } from '../../core/resource'; +import { APIPromise } from '../../core/api-promise'; +import { + DomainVerificationsPage, + type DomainVerificationsPageParams, + PagePromise, +} from '../../core/pagination'; import { RequestOptions } from '../../internal/request-options'; export class DomainVerifications extends APIResource { diff --git a/src/resources/organizations/invites.ts b/src/resources/organizations/invites.ts index b8f3540..5dded81 100644 --- a/src/resources/organizations/invites.ts +++ b/src/resources/organizations/invites.ts @@ -1,7 +1,7 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { APIResource } from '../../resource'; -import { APIPromise } from '../../api-promise'; +import { APIResource } from '../../core/resource'; +import { APIPromise } from '../../core/api-promise'; import { RequestOptions } from '../../internal/request-options'; export class Invites extends APIResource { diff --git a/src/resources/organizations/organizations.ts b/src/resources/organizations/organizations.ts index bdba148..b0b452d 100644 --- a/src/resources/organizations/organizations.ts +++ b/src/resources/organizations/organizations.ts @@ -1,6 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { APIResource } from '../../resource'; +import { APIResource } from '../../core/resource'; import * as Shared from '../shared'; import * as DomainVerificationsAPI from './domain-verifications'; import { @@ -46,14 +46,14 @@ import { SSOConfigurations, SSOConfigurationsSSOConfigurationsPage, } from './sso-configurations'; -import { APIPromise } from '../../api-promise'; +import { APIPromise } from '../../core/api-promise'; import { MembersPage, type MembersPageParams, OrganizationsPage, type OrganizationsPageParams, PagePromise, -} from '../../pagination'; +} from '../../core/pagination'; import { RequestOptions } from '../../internal/request-options'; export class Organizations extends APIResource { diff --git a/src/resources/organizations/sso-configurations.ts b/src/resources/organizations/sso-configurations.ts index 83e5205..a447375 100644 --- a/src/resources/organizations/sso-configurations.ts +++ b/src/resources/organizations/sso-configurations.ts @@ -1,8 +1,8 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { APIResource } from '../../resource'; -import { APIPromise } from '../../api-promise'; -import { PagePromise, SSOConfigurationsPage, type SSOConfigurationsPageParams } from '../../pagination'; +import { APIResource } from '../../core/resource'; +import { APIPromise } from '../../core/api-promise'; +import { PagePromise, SSOConfigurationsPage, type SSOConfigurationsPageParams } from '../../core/pagination'; import { RequestOptions } from '../../internal/request-options'; export class SSOConfigurations extends APIResource { diff --git a/src/resources/projects/policies.ts b/src/resources/projects/policies.ts index 07d3d09..ea39ec5 100644 --- a/src/resources/projects/policies.ts +++ b/src/resources/projects/policies.ts @@ -1,8 +1,8 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { APIResource } from '../../resource'; -import { APIPromise } from '../../api-promise'; -import { PagePromise, PoliciesPage, type PoliciesPageParams } from '../../pagination'; +import { APIResource } from '../../core/resource'; +import { APIPromise } from '../../core/api-promise'; +import { PagePromise, PoliciesPage, type PoliciesPageParams } from '../../core/pagination'; import { RequestOptions } from '../../internal/request-options'; export class Policies extends APIResource { diff --git a/src/resources/projects/projects.ts b/src/resources/projects/projects.ts index 7ca91c8..3f3967a 100644 --- a/src/resources/projects/projects.ts +++ b/src/resources/projects/projects.ts @@ -1,6 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { APIResource } from '../../resource'; +import { APIResource } from '../../core/resource'; import * as Shared from '../shared'; import * as PoliciesAPI from './policies'; import { @@ -16,8 +16,8 @@ import { ProjectPolicy, ProjectRole, } from './policies'; -import { APIPromise } from '../../api-promise'; -import { PagePromise, ProjectsPage, type ProjectsPageParams } from '../../pagination'; +import { APIPromise } from '../../core/api-promise'; +import { PagePromise, ProjectsPage, type ProjectsPageParams } from '../../core/pagination'; import { RequestOptions } from '../../internal/request-options'; export class Projects extends APIResource { diff --git a/src/resources/runners/configurations/configurations.ts b/src/resources/runners/configurations/configurations.ts index 0213678..db30ece 100644 --- a/src/resources/runners/configurations/configurations.ts +++ b/src/resources/runners/configurations/configurations.ts @@ -1,6 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { APIResource } from '../../../resource'; +import { APIResource } from '../../../core/resource'; import * as Shared from '../../shared'; import * as EnvironmentClassesAPI from './environment-classes'; import { @@ -47,7 +47,7 @@ import { ScmIntegrations, ScmIntegrationsIntegrationsPage, } from './scm-integrations'; -import { APIPromise } from '../../../api-promise'; +import { APIPromise } from '../../../core/api-promise'; import { RequestOptions } from '../../../internal/request-options'; export class Configurations extends APIResource { diff --git a/src/resources/runners/configurations/environment-classes.ts b/src/resources/runners/configurations/environment-classes.ts index 9e70d73..1db7137 100644 --- a/src/resources/runners/configurations/environment-classes.ts +++ b/src/resources/runners/configurations/environment-classes.ts @@ -1,11 +1,15 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { APIResource } from '../../../resource'; +import { APIResource } from '../../../core/resource'; import * as Shared from '../../shared'; import { EnvironmentClassesEnvironmentClassesPage } from '../../shared'; import * as RunnersAPI from '../runners'; -import { APIPromise } from '../../../api-promise'; -import { EnvironmentClassesPage, type EnvironmentClassesPageParams, PagePromise } from '../../../pagination'; +import { APIPromise } from '../../../core/api-promise'; +import { + EnvironmentClassesPage, + type EnvironmentClassesPageParams, + PagePromise, +} from '../../../core/pagination'; import { RequestOptions } from '../../../internal/request-options'; export class EnvironmentClasses extends APIResource { diff --git a/src/resources/runners/configurations/host-authentication-tokens.ts b/src/resources/runners/configurations/host-authentication-tokens.ts index 0b7240e..8196628 100644 --- a/src/resources/runners/configurations/host-authentication-tokens.ts +++ b/src/resources/runners/configurations/host-authentication-tokens.ts @@ -1,8 +1,8 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { APIResource } from '../../../resource'; -import { APIPromise } from '../../../api-promise'; -import { PagePromise, TokensPage, type TokensPageParams } from '../../../pagination'; +import { APIResource } from '../../../core/resource'; +import { APIPromise } from '../../../core/api-promise'; +import { PagePromise, TokensPage, type TokensPageParams } from '../../../core/pagination'; import { RequestOptions } from '../../../internal/request-options'; export class HostAuthenticationTokens extends APIResource { diff --git a/src/resources/runners/configurations/schema.ts b/src/resources/runners/configurations/schema.ts index 137908c..a7885dd 100644 --- a/src/resources/runners/configurations/schema.ts +++ b/src/resources/runners/configurations/schema.ts @@ -1,7 +1,7 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { APIResource } from '../../../resource'; -import { APIPromise } from '../../../api-promise'; +import { APIResource } from '../../../core/resource'; +import { APIPromise } from '../../../core/api-promise'; import { RequestOptions } from '../../../internal/request-options'; export class Schema extends APIResource { diff --git a/src/resources/runners/configurations/scm-integrations.ts b/src/resources/runners/configurations/scm-integrations.ts index d6dcc3f..ebdc52b 100644 --- a/src/resources/runners/configurations/scm-integrations.ts +++ b/src/resources/runners/configurations/scm-integrations.ts @@ -1,8 +1,8 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { APIResource } from '../../../resource'; -import { APIPromise } from '../../../api-promise'; -import { IntegrationsPage, type IntegrationsPageParams, PagePromise } from '../../../pagination'; +import { APIResource } from '../../../core/resource'; +import { APIPromise } from '../../../core/api-promise'; +import { IntegrationsPage, type IntegrationsPageParams, PagePromise } from '../../../core/pagination'; import { RequestOptions } from '../../../internal/request-options'; export class ScmIntegrations extends APIResource { diff --git a/src/resources/runners/policies.ts b/src/resources/runners/policies.ts index 4b71a77..0cdd4c1 100644 --- a/src/resources/runners/policies.ts +++ b/src/resources/runners/policies.ts @@ -1,8 +1,8 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { APIResource } from '../../resource'; -import { APIPromise } from '../../api-promise'; -import { PagePromise, PoliciesPage, type PoliciesPageParams } from '../../pagination'; +import { APIResource } from '../../core/resource'; +import { APIPromise } from '../../core/api-promise'; +import { PagePromise, PoliciesPage, type PoliciesPageParams } from '../../core/pagination'; import { RequestOptions } from '../../internal/request-options'; export class Policies extends APIResource { diff --git a/src/resources/runners/runners.ts b/src/resources/runners/runners.ts index 4efa8a4..0925d50 100644 --- a/src/resources/runners/runners.ts +++ b/src/resources/runners/runners.ts @@ -1,6 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { APIResource } from '../../resource'; +import { APIResource } from '../../core/resource'; import * as RunnersAPI from './runners'; import * as Shared from '../shared'; import * as PoliciesAPI from './policies'; @@ -26,8 +26,8 @@ import { FieldValidationError, ScmIntegrationValidationResult, } from './configurations/configurations'; -import { APIPromise } from '../../api-promise'; -import { PagePromise, RunnersPage, type RunnersPageParams } from '../../pagination'; +import { APIPromise } from '../../core/api-promise'; +import { PagePromise, RunnersPage, type RunnersPageParams } from '../../core/pagination'; import { RequestOptions } from '../../internal/request-options'; export class Runners extends APIResource { diff --git a/src/resources/secrets.ts b/src/resources/secrets.ts index 845d02e..62ceb78 100644 --- a/src/resources/secrets.ts +++ b/src/resources/secrets.ts @@ -1,9 +1,9 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { APIResource } from '../resource'; +import { APIResource } from '../core/resource'; import * as Shared from './shared'; -import { APIPromise } from '../api-promise'; -import { PagePromise, SecretsPage, type SecretsPageParams } from '../pagination'; +import { APIPromise } from '../core/api-promise'; +import { PagePromise, SecretsPage, type SecretsPageParams } from '../core/pagination'; import { RequestOptions } from '../internal/request-options'; export class Secrets extends APIResource { diff --git a/src/resources/shared.ts b/src/resources/shared.ts index e6c63f1..b771f1d 100644 --- a/src/resources/shared.ts +++ b/src/resources/shared.ts @@ -1,7 +1,7 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. import * as Shared from './shared'; -import { EnvironmentClassesPage, TaskExecutionsPage, TasksPage } from '../pagination'; +import { EnvironmentClassesPage, TaskExecutionsPage, TasksPage } from '../core/pagination'; /** * An AutomationTrigger represents a trigger for an automation action. The diff --git a/src/resources/users/pats.ts b/src/resources/users/pats.ts index d8037ac..6827d68 100644 --- a/src/resources/users/pats.ts +++ b/src/resources/users/pats.ts @@ -1,9 +1,13 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { APIResource } from '../../resource'; +import { APIResource } from '../../core/resource'; import * as Shared from '../shared'; -import { APIPromise } from '../../api-promise'; -import { PagePromise, PersonalAccessTokensPage, type PersonalAccessTokensPageParams } from '../../pagination'; +import { APIPromise } from '../../core/api-promise'; +import { + PagePromise, + PersonalAccessTokensPage, + type PersonalAccessTokensPageParams, +} from '../../core/pagination'; import { RequestOptions } from '../../internal/request-options'; export class Pats extends APIResource { diff --git a/src/resources/users/users.ts b/src/resources/users/users.ts index 63c3f75..4fb4bad 100644 --- a/src/resources/users/users.ts +++ b/src/resources/users/users.ts @@ -1,6 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { APIResource } from '../../resource'; +import { APIResource } from '../../core/resource'; import * as Shared from '../shared'; import * as PatsAPI from './pats'; import { @@ -13,7 +13,7 @@ import { PersonalAccessToken, PersonalAccessTokensPersonalAccessTokensPage, } from './pats'; -import { APIPromise } from '../../api-promise'; +import { APIPromise } from '../../core/api-promise'; import { RequestOptions } from '../../internal/request-options'; export class Users extends APIResource { diff --git a/src/uploads.ts b/src/uploads.ts index 79d3073..b2ef647 100644 --- a/src/uploads.ts +++ b/src/uploads.ts @@ -1,2 +1,2 @@ -export { type Uploadable } from './internal/uploads'; -export { toFile, type ToFileInput } from './internal/to-file'; +/** @deprecated Import from ./core/uploads instead */ +export * from './core/uploads'; diff --git a/tests/form.test.ts b/tests/form.test.ts index 1dd9656..cb575ba 100644 --- a/tests/form.test.ts +++ b/tests/form.test.ts @@ -1,5 +1,5 @@ import { multipartFormRequestOptions, createForm } from '@gitpod/sdk/internal/uploads'; -import { toFile } from '@gitpod/sdk/uploads'; +import { toFile } from '@gitpod/sdk/core/uploads'; describe('form data validation', () => { test('valid values do not error', async () => { diff --git a/tests/index.test.ts b/tests/index.test.ts index 24fd099..afe3fed 100644 --- a/tests/index.test.ts +++ b/tests/index.test.ts @@ -1,6 +1,6 @@ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details. -import { APIPromise } from '@gitpod/sdk/api-promise'; +import { APIPromise } from '@gitpod/sdk/core/api-promise'; import util from 'node:util'; import Gitpod from '@gitpod/sdk'; diff --git a/tests/uploads.test.ts b/tests/uploads.test.ts index 7b28bb5..d18eb6c 100644 --- a/tests/uploads.test.ts +++ b/tests/uploads.test.ts @@ -1,6 +1,6 @@ import fs from 'fs'; import type { ResponseLike } from '@gitpod/sdk/internal/to-file'; -import { toFile } from '@gitpod/sdk/uploads'; +import { toFile } from '@gitpod/sdk/core/uploads'; import { File } from 'node:buffer'; class MyClass { @@ -97,7 +97,7 @@ describe('missing File error message', () => { }); test('is thrown', async () => { - const uploads = await import('@gitpod/sdk/uploads'); + const uploads = await import('@gitpod/sdk/core/uploads'); await expect( uploads.toFile(mockResponse({ url: 'https://example.com/my/audio.mp3' })), ).rejects.toMatchInlineSnapshot( From dab243394f6b0f60cedc65f3eabcf1bfe64ed640 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 3 Apr 2025 06:54:56 +0000 Subject: [PATCH 21/26] fix(client): send `X-Stainless-Timeout` in seconds (#63) --- src/client.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client.ts b/src/client.ts index ef0b007..8f973c0 100644 --- a/src/client.ts +++ b/src/client.ts @@ -835,7 +835,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), From 38e00c9995d8528c361bf709d3951a0f00238ada Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Thu, 3 Apr 2025 07:20:40 +0000 Subject: [PATCH 22/26] chore(internal): add aliases for Record and Array (#64) --- src/internal/builtin-types.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) 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<T>` type so we can + * easily alias it in import statements if there are name clashes. + */ +type _Array<T> = Array<T>; + +/** + * An alias to the builtin `Record<K, T>` type so we can + * easily alias it in import statements if there are name clashes. + */ +type _Record<K extends keyof any, T> = Record<K, T>; + export type { + _Array as Array, _BodyInit as BodyInit, _HeadersInit as HeadersInit, + _Record as Record, _RequestInfo as RequestInfo, _RequestInit as RequestInit, _Response as Response, From 62c4790ed0515d7644fca6075b5d9304bd4b1642 Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 4 Apr 2025 08:18:11 +0000 Subject: [PATCH 23/26] chore(client): make jsonl methods consistent with other streaming methods (#65) --- api.md | 2 +- src/resources/events.ts | 5 +- tests/internal/decoders/line.test.ts | 128 +++++++++++++++++++++++++++ 3 files changed, 133 insertions(+), 2 deletions(-) create mode 100644 tests/internal/decoders/line.test.ts diff --git a/api.md b/api.md index 8e80f38..4a2d257 100644 --- a/api.md +++ b/api.md @@ -174,7 +174,7 @@ Types: Methods: - <code title="post /gitpod.v1.EventService/ListAuditLogs">client.events.<a href="./src/resources/events.ts">list</a>({ ...params }) -> EventListResponsesEntriesPage</code> -- <code title="post /gitpod.v1.EventService/WatchEvents">client.events.<a href="./src/resources/events.ts">watch</a>({ ...params }) -> JSONLDecoder<EventWatchResponse></code> +- <code title="post /gitpod.v1.EventService/WatchEvents">client.events.<a href="./src/resources/events.ts">watch</a>({ ...params }) -> EventWatchResponse</code> # Groups diff --git a/src/resources/events.ts b/src/resources/events.ts index 68a011a..bc5d412 100644 --- a/src/resources/events.ts +++ b/src/resources/events.ts @@ -79,9 +79,12 @@ export class Events extends APIResource { { 'Content-Type': 'application/jsonl', Accept: 'application/jsonl' }, options?.headers, ]), + stream: true, __binaryResponse: true, }) - ._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller)); + ._thenUnwrap((_, props) => JSONLDecoder.fromResponse(props.response, props.controller)) as APIPromise< + JSONLDecoder<EventWatchResponse> + >; } } diff --git a/tests/internal/decoders/line.test.ts b/tests/internal/decoders/line.test.ts new file mode 100644 index 0000000..9f45693 --- /dev/null +++ b/tests/internal/decoders/line.test.ts @@ -0,0 +1,128 @@ +import { findDoubleNewlineIndex, LineDecoder } from '@gitpod/sdk/internal/decoders/line'; + +function decodeChunks(chunks: string[], { flush }: { flush: boolean } = { flush: false }): string[] { + const decoder = new LineDecoder(); + const lines: string[] = []; + for (const chunk of chunks) { + lines.push(...decoder.decode(chunk)); + } + + if (flush) { + lines.push(...decoder.flush()); + } + + return lines; +} + +describe('line decoder', () => { + test('basic', () => { + // baz is not included because the line hasn't ended yet + expect(decodeChunks(['foo', ' bar\nbaz'])).toEqual(['foo bar']); + }); + + test('basic with \\r', () => { + expect(decodeChunks(['foo', ' bar\r\nbaz'])).toEqual(['foo bar']); + expect(decodeChunks(['foo', ' bar\r\nbaz'], { flush: true })).toEqual(['foo bar', 'baz']); + }); + + test('trailing new lines', () => { + expect(decodeChunks(['foo', ' bar', 'baz\n', 'thing\n'])).toEqual(['foo barbaz', 'thing']); + }); + + test('trailing new lines with \\r', () => { + expect(decodeChunks(['foo', ' bar', 'baz\r\n', 'thing\r\n'])).toEqual(['foo barbaz', 'thing']); + }); + + test('escaped new lines', () => { + expect(decodeChunks(['foo', ' bar\\nbaz\n'])).toEqual(['foo bar\\nbaz']); + }); + + test('escaped new lines with \\r', () => { + expect(decodeChunks(['foo', ' bar\\r\\nbaz\n'])).toEqual(['foo bar\\r\\nbaz']); + }); + + test('\\r & \\n split across multiple chunks', () => { + expect(decodeChunks(['foo\r', '\n', 'bar'], { flush: true })).toEqual(['foo', 'bar']); + }); + + test('single \\r', () => { + expect(decodeChunks(['foo\r', 'bar'], { flush: true })).toEqual(['foo', 'bar']); + }); + + test('double \\r', () => { + expect(decodeChunks(['foo\r', 'bar\r'], { flush: true })).toEqual(['foo', 'bar']); + expect(decodeChunks(['foo\r', '\r', 'bar'], { flush: true })).toEqual(['foo', '', 'bar']); + // implementation detail that we don't yield the single \r line until a new \r or \n is encountered + expect(decodeChunks(['foo\r', '\r', 'bar'], { flush: false })).toEqual(['foo']); + }); + + test('double \\r then \\r\\n', () => { + expect(decodeChunks(['foo\r', '\r', '\r', '\n', 'bar', '\n'])).toEqual(['foo', '', '', 'bar']); + expect(decodeChunks(['foo\n', '\n', '\n', 'bar', '\n'])).toEqual(['foo', '', '', 'bar']); + }); + + test('double newline', () => { + expect(decodeChunks(['foo\n\nbar'], { flush: true })).toEqual(['foo', '', 'bar']); + expect(decodeChunks(['foo', '\n', '\nbar'], { flush: true })).toEqual(['foo', '', 'bar']); + expect(decodeChunks(['foo\n', '\n', 'bar'], { flush: true })).toEqual(['foo', '', 'bar']); + expect(decodeChunks(['foo', '\n', '\n', 'bar'], { flush: true })).toEqual(['foo', '', 'bar']); + }); + + test('multi-byte characters across chunks', () => { + const decoder = new LineDecoder(); + + // bytes taken from the string 'известни' and arbitrarily split + // so that some multi-byte characters span multiple chunks + expect(decoder.decode(new Uint8Array([0xd0]))).toHaveLength(0); + expect(decoder.decode(new Uint8Array([0xb8, 0xd0, 0xb7, 0xd0]))).toHaveLength(0); + expect( + decoder.decode(new Uint8Array([0xb2, 0xd0, 0xb5, 0xd1, 0x81, 0xd1, 0x82, 0xd0, 0xbd, 0xd0, 0xb8])), + ).toHaveLength(0); + + const decoded = decoder.decode(new Uint8Array([0xa])); + expect(decoded).toEqual(['известни']); + }); + + test('flushing trailing newlines', () => { + expect(decodeChunks(['foo\n', '\nbar'], { flush: true })).toEqual(['foo', '', 'bar']); + }); + + test('flushing empty buffer', () => { + expect(decodeChunks([], { flush: true })).toEqual([]); + }); +}); + +describe('findDoubleNewlineIndex', () => { + test('finds \\n\\n', () => { + expect(findDoubleNewlineIndex(new TextEncoder().encode('foo\n\nbar'))).toBe(5); + expect(findDoubleNewlineIndex(new TextEncoder().encode('\n\nbar'))).toBe(2); + expect(findDoubleNewlineIndex(new TextEncoder().encode('foo\n\n'))).toBe(5); + expect(findDoubleNewlineIndex(new TextEncoder().encode('\n\n'))).toBe(2); + }); + + test('finds \\r\\r', () => { + expect(findDoubleNewlineIndex(new TextEncoder().encode('foo\r\rbar'))).toBe(5); + expect(findDoubleNewlineIndex(new TextEncoder().encode('\r\rbar'))).toBe(2); + expect(findDoubleNewlineIndex(new TextEncoder().encode('foo\r\r'))).toBe(5); + expect(findDoubleNewlineIndex(new TextEncoder().encode('\r\r'))).toBe(2); + }); + + test('finds \\r\\n\\r\\n', () => { + expect(findDoubleNewlineIndex(new TextEncoder().encode('foo\r\n\r\nbar'))).toBe(7); + expect(findDoubleNewlineIndex(new TextEncoder().encode('\r\n\r\nbar'))).toBe(4); + expect(findDoubleNewlineIndex(new TextEncoder().encode('foo\r\n\r\n'))).toBe(7); + expect(findDoubleNewlineIndex(new TextEncoder().encode('\r\n\r\n'))).toBe(4); + }); + + test('returns -1 when no double newline found', () => { + expect(findDoubleNewlineIndex(new TextEncoder().encode('foo\nbar'))).toBe(-1); + expect(findDoubleNewlineIndex(new TextEncoder().encode('foo\rbar'))).toBe(-1); + expect(findDoubleNewlineIndex(new TextEncoder().encode('foo\r\nbar'))).toBe(-1); + expect(findDoubleNewlineIndex(new TextEncoder().encode(''))).toBe(-1); + }); + + test('handles incomplete patterns', () => { + expect(findDoubleNewlineIndex(new TextEncoder().encode('foo\r\n\r'))).toBe(-1); + expect(findDoubleNewlineIndex(new TextEncoder().encode('foo\r\n'))).toBe(-1); + }); +}); From 8aa007bc39d87e8b96861748a23d4faa5d084c8a Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 4 Apr 2025 08:28:47 +0000 Subject: [PATCH 24/26] fix(api): improve type resolution when importing as a package (#66) --- packages/mcp-server/src/tools.ts | 1 + 1 file changed, 1 insertion(+) create mode 100644 packages/mcp-server/src/tools.ts diff --git a/packages/mcp-server/src/tools.ts b/packages/mcp-server/src/tools.ts new file mode 100644 index 0000000..7e516de --- /dev/null +++ b/packages/mcp-server/src/tools.ts @@ -0,0 +1 @@ +export * from './tools/index'; From 65686bf96f2a2147c620810605bc66876ec0c13e Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 5 Apr 2025 02:20:11 +0000 Subject: [PATCH 25/26] fix(mcp): remove unused tools.ts (#67) --- packages/mcp-server/src/tools.ts | 1 - 1 file changed, 1 deletion(-) delete mode 100644 packages/mcp-server/src/tools.ts diff --git a/packages/mcp-server/src/tools.ts b/packages/mcp-server/src/tools.ts deleted file mode 100644 index 7e516de..0000000 --- a/packages/mcp-server/src/tools.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './tools/index'; From 0a3af36bcba59a86c598fd6d9b831304a00f312b Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Sat, 5 Apr 2025 02:20:34 +0000 Subject: [PATCH 26/26] release: 0.5.1 --- .release-please-manifest.json | 2 +- CHANGELOG.md | 39 +++++++++++++++++++++++++++++++++++ package.json | 2 +- src/version.ts | 2 +- 4 files changed, 42 insertions(+), 3 deletions(-) diff --git a/.release-please-manifest.json b/.release-please-manifest.json index f1c1e58..210d290 100644 --- a/.release-please-manifest.json +++ b/.release-please-manifest.json @@ -1,3 +1,3 @@ { - ".": "0.5.0" + ".": "0.5.1" } diff --git a/CHANGELOG.md b/CHANGELOG.md index b82eb11..469d199 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,44 @@ # Changelog +## 0.5.1 (2025-04-05) + +Full Changelog: [v0.5.0...v0.5.1](https://github.com/gitpod-io/gitpod-sdk-typescript/compare/v0.5.0...v0.5.1) + +### 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)) +* **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:** 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 + +* **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:** 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 ([#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:** 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:** 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)) +* **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 + +* 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/package.json b/package.json index dae603a..e1de88a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@gitpod/sdk", - "version": "0.5.0", + "version": "0.5.1", "description": "The official TypeScript library for the Gitpod API", "author": "Gitpod <dev-feedback@gitpod.com>", "types": "dist/index.d.ts", diff --git a/src/version.ts b/src/version.ts index 1f5d158..44c3338 100644 --- a/src/version.ts +++ b/src/version.ts @@ -1 +1 @@ -export const VERSION = '0.5.0'; // x-release-please-version +export const VERSION = '0.5.1'; // x-release-please-version