Skip to content

Commit

Permalink
feat(package): export a root error type (#338)
Browse files Browse the repository at this point in the history
  • Loading branch information
stainless-bot authored Sep 25, 2023
1 parent fd2337b commit 462bcda
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 16 deletions.
24 changes: 15 additions & 9 deletions src/core.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { VERSION } from './version';
import { Stream } from './streaming';
import { APIError, APIConnectionError, APIConnectionTimeoutError, APIUserAbortError } from './error';
import {
OpenAIError,
APIError,
APIConnectionError,
APIConnectionTimeoutError,
APIUserAbortError,
} from './error';
import {
kind as shimsKind,
type Readable,
Expand Down Expand Up @@ -440,7 +446,7 @@ export abstract class APIClient {
if (value === null) {
return `${encodeURIComponent(key)}=`;
}
throw new Error(
throw new OpenAIError(
`Cannot stringify type ${typeof value}; Expected string, number, boolean, or null. If you need to pass nested query parameters, you can manually encode them, e.g. { query: { 'foo[key1]': value1, 'foo[key2]': value2 } }, and please open a GitHub issue requesting better support for your use case.`,
);
})
Expand Down Expand Up @@ -599,7 +605,7 @@ export abstract class AbstractPage<Item> implements AsyncIterable<Item> {
async getNextPage(): Promise<this> {
const nextInfo = this.nextPageInfo();
if (!nextInfo) {
throw new Error(
throw new OpenAIError(
'No next page expected; please check `.hasNextPage()` before calling `.getNextPage()`.',
);
}
Expand Down Expand Up @@ -925,10 +931,10 @@ export const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve

const validatePositiveInteger = (name: string, n: unknown): number => {
if (typeof n !== 'number' || !Number.isInteger(n)) {
throw new Error(`${name} must be an integer`);
throw new OpenAIError(`${name} must be an integer`);
}
if (n < 0) {
throw new Error(`${name} must be a positive integer`);
throw new OpenAIError(`${name} must be a positive integer`);
}
return n;
};
Expand All @@ -939,7 +945,7 @@ export const castToError = (err: any): Error => {
};

export const ensurePresent = <T>(value: T | null | undefined): T => {
if (value == null) throw new Error(`Expected a value to be given but received ${value} instead.`);
if (value == null) throw new OpenAIError(`Expected a value to be given but received ${value} instead.`);
return value;
};

Expand All @@ -962,14 +968,14 @@ export const coerceInteger = (value: unknown): number => {
if (typeof value === 'number') return Math.round(value);
if (typeof value === 'string') return parseInt(value, 10);

throw new Error(`Could not coerce ${value} (type: ${typeof value}) into a number`);
throw new OpenAIError(`Could not coerce ${value} (type: ${typeof value}) into a number`);
};

export const coerceFloat = (value: unknown): number => {
if (typeof value === 'number') return value;
if (typeof value === 'string') return parseFloat(value);

throw new Error(`Could not coerce ${value} (type: ${typeof value}) into a number`);
throw new OpenAIError(`Could not coerce ${value} (type: ${typeof value}) into a number`);
};

export const coerceBoolean = (value: unknown): boolean => {
Expand Down Expand Up @@ -1073,5 +1079,5 @@ export const toBase64 = (str: string | null | undefined): string => {
return btoa(str);
}

throw new Error('Cannot generate b64 string; Expected `Buffer` or `btoa` to be defined');
throw new OpenAIError('Cannot generate b64 string; Expected `Buffer` or `btoa` to be defined');
};
4 changes: 3 additions & 1 deletion src/error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

import { castToError, Headers } from './core';

export class APIError extends Error {
export class OpenAIError extends Error {}

export class APIError extends OpenAIError {
readonly status: number | undefined;
readonly headers: Headers | undefined;
readonly error: Object | undefined;
Expand Down
6 changes: 4 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ export class OpenAI extends Core.APIClient {
...opts
}: ClientOptions = {}) {
if (apiKey === undefined) {
throw new Error(
throw new Errors.OpenAIError(
"The OPENAI_API_KEY environment variable is missing or empty; either provide it, or instantiate the OpenAI client with an apiKey option, like new OpenAI({ apiKey: 'my apiKey' }).",
);
}
Expand All @@ -116,7 +116,7 @@ export class OpenAI extends Core.APIClient {
};

if (!options.dangerouslyAllowBrowser && Core.isRunningInBrowser()) {
throw new Error(
throw new Errors.OpenAIError(
"It looks like you're running in a browser-like environment.\n\nThis is disabled by default, as it risks exposing your secret API credentials to attackers.\nIf you understand the risks and have appropriate mitigations in place,\nyou can set the `dangerouslyAllowBrowser` option to `true`, e.g.,\n\nnew OpenAI({ apiKey, dangerouslyAllowBrowser: true });\n\nhttps://help.openai.com/en/articles/5112595-best-practices-for-api-key-safety\n",
);
}
Expand Down Expand Up @@ -164,6 +164,7 @@ export class OpenAI extends Core.APIClient {

static OpenAI = this;

static OpenAIError = Errors.OpenAIError;
static APIError = Errors.APIError;
static APIConnectionError = Errors.APIConnectionError;
static APIConnectionTimeoutError = Errors.APIConnectionTimeoutError;
Expand All @@ -179,6 +180,7 @@ export class OpenAI extends Core.APIClient {
}

export const {
OpenAIError,
APIError,
APIConnectionError,
APIConnectionTimeoutError,
Expand Down
9 changes: 5 additions & 4 deletions src/streaming.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { type Response } from './_shims/index';
import { OpenAIError } from './error';

type Bytes = string | ArrayBuffer | Uint8Array | Buffer | null | undefined;

Expand All @@ -23,7 +24,7 @@ export class Stream<Item> implements AsyncIterable<Item> {
private async *iterMessages(): AsyncGenerator<ServerSentEvent, void, unknown> {
if (!this.response.body) {
this.controller.abort();
throw new Error(`Attempted to iterate over a response with no body`);
throw new OpenAIError(`Attempted to iterate over a response with no body`);
}
const lineDecoder = new LineDecoder();

Expand Down Expand Up @@ -198,7 +199,7 @@ class LineDecoder {
return Buffer.from(bytes).toString();
}

throw new Error(
throw new OpenAIError(
`Unexpected: received non-Uint8Array (${bytes.constructor.name}) stream chunk in an environment with a global "Buffer" defined, which this library assumes to be Node. Please report this error.`,
);
}
Expand All @@ -210,14 +211,14 @@ class LineDecoder {
return this.textDecoder.decode(bytes);
}

throw new Error(
throw new OpenAIError(
`Unexpected: received non-Uint8Array/ArrayBuffer (${
(bytes as any).constructor.name
}) in a web platform. Please report this error.`,
);
}

throw new Error(
throw new OpenAIError(
`Unexpected: neither Buffer nor TextDecoder are available as globals. Please report this error.`,
);
}
Expand Down

0 comments on commit 462bcda

Please sign in to comment.