Skip to content

Commit e4008c3

Browse files
chore(client): move misc public files to new core/ directory, deprecate old paths (#62)
1 parent b79e1f2 commit e4008c3

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+1589
-1557
lines changed

Diff for: src/api-promise.ts

+2-92
Original file line numberDiff line numberDiff line change
@@ -1,92 +1,2 @@
1-
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2-
3-
import { type Gitpod } from './client';
4-
5-
import { type PromiseOrValue } from './internal/types';
6-
import { APIResponseProps, defaultParseResponse } from './internal/parse';
7-
8-
/**
9-
* A subclass of `Promise` providing additional helper methods
10-
* for interacting with the SDK.
11-
*/
12-
export class APIPromise<T> extends Promise<T> {
13-
private parsedPromise: Promise<T> | undefined;
14-
#client: Gitpod;
15-
16-
constructor(
17-
client: Gitpod,
18-
private responsePromise: Promise<APIResponseProps>,
19-
private parseResponse: (
20-
client: Gitpod,
21-
props: APIResponseProps,
22-
) => PromiseOrValue<T> = defaultParseResponse,
23-
) {
24-
super((resolve) => {
25-
// this is maybe a bit weird but this has to be a no-op to not implicitly
26-
// parse the response body; instead .then, .catch, .finally are overridden
27-
// to parse the response
28-
resolve(null as any);
29-
});
30-
this.#client = client;
31-
}
32-
33-
_thenUnwrap<U>(transform: (data: T, props: APIResponseProps) => U): APIPromise<U> {
34-
return new APIPromise(this.#client, this.responsePromise, async (client, props) =>
35-
transform(await this.parseResponse(client, props), props),
36-
);
37-
}
38-
39-
/**
40-
* Gets the raw `Response` instance instead of parsing the response
41-
* data.
42-
*
43-
* If you want to parse the response body but still get the `Response`
44-
* instance, you can use {@link withResponse()}.
45-
*
46-
* 👋 Getting the wrong TypeScript type for `Response`?
47-
* Try setting `"moduleResolution": "NodeNext"` or add `"lib": ["DOM"]`
48-
* to your `tsconfig.json`.
49-
*/
50-
asResponse(): Promise<Response> {
51-
return this.responsePromise.then((p) => p.response);
52-
}
53-
54-
/**
55-
* Gets the parsed response data and the raw `Response` instance.
56-
*
57-
* If you just want to get the raw `Response` instance without parsing it,
58-
* you can use {@link asResponse()}.
59-
*
60-
* 👋 Getting the wrong TypeScript type for `Response`?
61-
* Try setting `"moduleResolution": "NodeNext"` or add `"lib": ["DOM"]`
62-
* to your `tsconfig.json`.
63-
*/
64-
async withResponse(): Promise<{ data: T; response: Response }> {
65-
const [data, response] = await Promise.all([this.parse(), this.asResponse()]);
66-
return { data, response };
67-
}
68-
69-
private parse(): Promise<T> {
70-
if (!this.parsedPromise) {
71-
this.parsedPromise = this.responsePromise.then((data) => this.parseResponse(this.#client, data));
72-
}
73-
return this.parsedPromise;
74-
}
75-
76-
override then<TResult1 = T, TResult2 = never>(
77-
onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null,
78-
onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null,
79-
): Promise<TResult1 | TResult2> {
80-
return this.parse().then(onfulfilled, onrejected);
81-
}
82-
83-
override catch<TResult = never>(
84-
onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | undefined | null,
85-
): Promise<T | TResult> {
86-
return this.parse().catch(onrejected);
87-
}
88-
89-
override finally(onfinally?: (() => void) | undefined | null): Promise<T> {
90-
return this.parse().finally(onfinally);
91-
}
92-
}
1+
/** @deprecated Import from ./core/api-promise instead */
2+
export * from './core/api-promise';

Diff for: src/client.ts

+5-5
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ import { getPlatformHeaders } from './internal/detect-platform';
1313
import * as Shims from './internal/shims';
1414
import * as Opts from './internal/request-options';
1515
import { VERSION } from './version';
16-
import * as Errors from './error';
17-
import * as Pagination from './pagination';
16+
import * as Errors from './core/error';
17+
import * as Pagination from './core/pagination';
1818
import {
1919
AbstractPage,
2020
type DomainVerificationsPageParams,
@@ -57,10 +57,10 @@ import {
5757
TasksPageResponse,
5858
type TokensPageParams,
5959
TokensPageResponse,
60-
} from './pagination';
61-
import * as Uploads from './uploads';
60+
} from './core/pagination';
61+
import * as Uploads from './core/uploads';
6262
import * as API from './resources/index';
63-
import { APIPromise } from './api-promise';
63+
import { APIPromise } from './core/api-promise';
6464
import { type Fetch } from './internal/builtin-types';
6565
import { HeadersLike, NullableHeaders, buildHeaders } from './internal/headers';
6666
import { FinalRequestOptions, RequestOptions } from './internal/request-options';

Diff for: src/core/README.md

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# `core`
2+
3+
This directory holds public modules implementing non-resource-specific SDK functionality.

Diff for: src/core/api-promise.ts

+92
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2+
3+
import { type Gitpod } from '../client';
4+
5+
import { type PromiseOrValue } from '../internal/types';
6+
import { APIResponseProps, defaultParseResponse } from '../internal/parse';
7+
8+
/**
9+
* A subclass of `Promise` providing additional helper methods
10+
* for interacting with the SDK.
11+
*/
12+
export class APIPromise<T> extends Promise<T> {
13+
private parsedPromise: Promise<T> | undefined;
14+
#client: Gitpod;
15+
16+
constructor(
17+
client: Gitpod,
18+
private responsePromise: Promise<APIResponseProps>,
19+
private parseResponse: (
20+
client: Gitpod,
21+
props: APIResponseProps,
22+
) => PromiseOrValue<T> = defaultParseResponse,
23+
) {
24+
super((resolve) => {
25+
// this is maybe a bit weird but this has to be a no-op to not implicitly
26+
// parse the response body; instead .then, .catch, .finally are overridden
27+
// to parse the response
28+
resolve(null as any);
29+
});
30+
this.#client = client;
31+
}
32+
33+
_thenUnwrap<U>(transform: (data: T, props: APIResponseProps) => U): APIPromise<U> {
34+
return new APIPromise(this.#client, this.responsePromise, async (client, props) =>
35+
transform(await this.parseResponse(client, props), props),
36+
);
37+
}
38+
39+
/**
40+
* Gets the raw `Response` instance instead of parsing the response
41+
* data.
42+
*
43+
* If you want to parse the response body but still get the `Response`
44+
* instance, you can use {@link withResponse()}.
45+
*
46+
* 👋 Getting the wrong TypeScript type for `Response`?
47+
* Try setting `"moduleResolution": "NodeNext"` or add `"lib": ["DOM"]`
48+
* to your `tsconfig.json`.
49+
*/
50+
asResponse(): Promise<Response> {
51+
return this.responsePromise.then((p) => p.response);
52+
}
53+
54+
/**
55+
* Gets the parsed response data and the raw `Response` instance.
56+
*
57+
* If you just want to get the raw `Response` instance without parsing it,
58+
* you can use {@link asResponse()}.
59+
*
60+
* 👋 Getting the wrong TypeScript type for `Response`?
61+
* Try setting `"moduleResolution": "NodeNext"` or add `"lib": ["DOM"]`
62+
* to your `tsconfig.json`.
63+
*/
64+
async withResponse(): Promise<{ data: T; response: Response }> {
65+
const [data, response] = await Promise.all([this.parse(), this.asResponse()]);
66+
return { data, response };
67+
}
68+
69+
private parse(): Promise<T> {
70+
if (!this.parsedPromise) {
71+
this.parsedPromise = this.responsePromise.then((data) => this.parseResponse(this.#client, data));
72+
}
73+
return this.parsedPromise;
74+
}
75+
76+
override then<TResult1 = T, TResult2 = never>(
77+
onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null,
78+
onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null,
79+
): Promise<TResult1 | TResult2> {
80+
return this.parse().then(onfulfilled, onrejected);
81+
}
82+
83+
override catch<TResult = never>(
84+
onrejected?: ((reason: any) => TResult | PromiseLike<TResult>) | undefined | null,
85+
): Promise<T | TResult> {
86+
return this.parse().catch(onrejected);
87+
}
88+
89+
override finally(onfinally?: (() => void) | undefined | null): Promise<T> {
90+
return this.parse().finally(onfinally);
91+
}
92+
}

Diff for: src/core/error.ts

+140
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
// File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2+
3+
import { castToError } from '../internal/errors';
4+
import * as Shared from '../resources/shared';
5+
6+
export class GitpodError extends Error {}
7+
8+
export class APIError<
9+
TStatus extends number | undefined = number | undefined,
10+
THeaders extends Headers | undefined = Headers | undefined,
11+
TError extends Object | undefined = Object | undefined,
12+
> extends GitpodError {
13+
/** HTTP status for the response that caused the error */
14+
readonly status: TStatus;
15+
/** HTTP headers for the response that caused the error */
16+
readonly headers: THeaders;
17+
/** JSON body of the response that caused the error */
18+
readonly error: TError;
19+
20+
/**
21+
* The status code, which should be an enum value of
22+
* [google.rpc.Code][google.rpc.Code].
23+
*/
24+
readonly code?: Shared.ErrorCode | undefined;
25+
26+
constructor(status: TStatus, error: TError, message: string | undefined, headers: THeaders) {
27+
super(`${APIError.makeMessage(status, error, message)}`);
28+
this.status = status;
29+
this.headers = headers;
30+
this.error = error;
31+
32+
const data = error as Record<string, any>;
33+
this.code = data?.['code'];
34+
}
35+
36+
private static makeMessage(status: number | undefined, error: any, message: string | undefined) {
37+
const msg =
38+
error?.message ?
39+
typeof error.message === 'string' ?
40+
error.message
41+
: JSON.stringify(error.message)
42+
: error ? JSON.stringify(error)
43+
: message;
44+
45+
if (status && msg) {
46+
return `${status} ${msg}`;
47+
}
48+
if (status) {
49+
return `${status} status code (no body)`;
50+
}
51+
if (msg) {
52+
return msg;
53+
}
54+
return '(no status code or body)';
55+
}
56+
57+
static generate(
58+
status: number | undefined,
59+
errorResponse: Object | undefined,
60+
message: string | undefined,
61+
headers: Headers | undefined,
62+
): APIError {
63+
if (!status || !headers) {
64+
return new APIConnectionError({ message, cause: castToError(errorResponse) });
65+
}
66+
67+
const error = errorResponse as Record<string, any>;
68+
69+
if (status === 400) {
70+
return new BadRequestError(status, error, message, headers);
71+
}
72+
73+
if (status === 401) {
74+
return new AuthenticationError(status, error, message, headers);
75+
}
76+
77+
if (status === 403) {
78+
return new PermissionDeniedError(status, error, message, headers);
79+
}
80+
81+
if (status === 404) {
82+
return new NotFoundError(status, error, message, headers);
83+
}
84+
85+
if (status === 409) {
86+
return new ConflictError(status, error, message, headers);
87+
}
88+
89+
if (status === 422) {
90+
return new UnprocessableEntityError(status, error, message, headers);
91+
}
92+
93+
if (status === 429) {
94+
return new RateLimitError(status, error, message, headers);
95+
}
96+
97+
if (status >= 500) {
98+
return new InternalServerError(status, error, message, headers);
99+
}
100+
101+
return new APIError(status, error, message, headers);
102+
}
103+
}
104+
105+
export class APIUserAbortError extends APIError<undefined, undefined, undefined> {
106+
constructor({ message }: { message?: string } = {}) {
107+
super(undefined, undefined, message || 'Request was aborted.', undefined);
108+
}
109+
}
110+
111+
export class APIConnectionError extends APIError<undefined, undefined, undefined> {
112+
constructor({ message, cause }: { message?: string | undefined; cause?: Error | undefined }) {
113+
super(undefined, undefined, message || 'Connection error.', undefined);
114+
// in some environments the 'cause' property is already declared
115+
// @ts-ignore
116+
if (cause) this.cause = cause;
117+
}
118+
}
119+
120+
export class APIConnectionTimeoutError extends APIConnectionError {
121+
constructor({ message }: { message?: string } = {}) {
122+
super({ message: message ?? 'Request timed out.' });
123+
}
124+
}
125+
126+
export class BadRequestError extends APIError<400, Headers> {}
127+
128+
export class AuthenticationError extends APIError<401, Headers> {}
129+
130+
export class PermissionDeniedError extends APIError<403, Headers> {}
131+
132+
export class NotFoundError extends APIError<404, Headers> {}
133+
134+
export class ConflictError extends APIError<409, Headers> {}
135+
136+
export class UnprocessableEntityError extends APIError<422, Headers> {}
137+
138+
export class RateLimitError extends APIError<429, Headers> {}
139+
140+
export class InternalServerError extends APIError<number, Headers> {}

0 commit comments

Comments
 (0)