Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .npmignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
node_modules
yarn-error.log
.github
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ We are keen for your feedback; please open an [issue](https://www.github.com/lit

The following runtimes are supported:

- Node.js version 12 or higher.
- Node.js 16 LTS or later ([non-EOL](https://endoflife.date/nodejs)) versions.
- Deno v1.28.0 or higher (experimental).
Use `import Lithic from "npm:lithic"`.

Expand Down
81 changes: 2 additions & 79 deletions core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { Readable } from 'stream';

import { VERSION } from './version';
import { Stream } from './streaming';
import { APIError, APIConnectionError, APIConnectionTimeoutError } from './error';
import { Fetch, getDefaultAgent, getFetch } from './fetch-polyfill';

const MAX_RETRIES = 2;
Expand Down Expand Up @@ -543,84 +544,6 @@ export type APIResponse<T> = T & {
responseHeaders: Headers;
};

export class APIError extends Error {
readonly status: number | undefined;
readonly headers: Headers | undefined;
readonly error: Object | undefined;

constructor(
status: number | undefined,
error: Object | undefined,
message: string | undefined,
headers: Headers | undefined,
) {
super(message || (error as any)?.message);
this.status = status;
this.headers = headers;
this.error = error;
}

static generate(
status: number | undefined,
error: Object | undefined,
message: string | undefined,
headers: Headers | undefined,
) {
if (!status) return new APIConnectionError({ cause: castToError(error) });

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 BadRequestError extends APIError {
override readonly status: 400 = 400;
}
export class AuthenticationError extends APIError {
override readonly status: 401 = 401;
}
export class PermissionDeniedError extends APIError {
override readonly status: 403 = 403;
}
export class NotFoundError extends APIError {
override readonly status: 404 = 404;
}
export class ConflictError extends APIError {
override readonly status: 409 = 409;
}
export class UnprocessableEntityError extends APIError {
override readonly status: 422 = 422;
}
export class RateLimitError extends APIError {
override readonly status: 429 = 429;
}
export class InternalServerError extends APIError {}

export class APIConnectionError extends APIError {
override readonly status: undefined = undefined;

constructor({ message, cause }: { message?: string; cause?: Error | undefined }) {
super(undefined, undefined, message || 'Connection error.', undefined);
// eslint-disable-next-line
// @ts-ignore
if (cause) this.cause = cause;
}
}

export class APIConnectionTimeoutError extends APIConnectionError {
constructor() {
super({ message: 'Request timed out.' });
}
}

declare const Deno: any;
type Arch = 'x32' | 'x64' | 'arm' | 'arm64' | `other:${string}` | 'unknown';
type PlatformName =
Expand Down Expand Up @@ -741,7 +664,7 @@ const validatePositiveInteger = (name: string, n: number) => {
return n;
};

const castToError = (err: any): Error => {
export const castToError = (err: any): Error => {
if (err instanceof Error) return err;
return new Error(err);
};
Expand Down
115 changes: 115 additions & 0 deletions error.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
// File generated from our OpenAPI spec by Stainless.

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

export class APIError extends Error {
readonly status: number | undefined;
readonly headers: Headers | undefined;
readonly error: Object | undefined;

constructor(
status: number | undefined,
error: Object | undefined,
message: string | undefined,
headers: Headers | undefined,
) {
super(message || (error as any)?.message || 'Unknown error occurred.');
this.status = status;
this.headers = headers;
this.error = error;
}

static generate(
status: number | undefined,
errorResponse: Object | undefined,
message: string | undefined,
headers: Headers | undefined,
) {
if (!status) {
return new APIConnectionError({ 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 APIConnectionError extends APIError {
override readonly status: undefined = undefined;

constructor({ message, cause }: { message?: string; 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() {
super({ message: 'Request timed out.' });
}
}

export class BadRequestError extends APIError {
override readonly status: 400 = 400;
}

export class AuthenticationError extends APIError {
override readonly status: 401 = 401;
}

export class PermissionDeniedError extends APIError {
override readonly status: 403 = 403;
}

export class NotFoundError extends APIError {
override readonly status: 404 = 404;
}

export class ConflictError extends APIError {
override readonly status: 409 = 409;
}

export class UnprocessableEntityError extends APIError {
override readonly status: 422 = 422;
}

export class RateLimitError extends APIError {
override readonly status: 429 = 429;
}

export class InternalServerError extends APIError {}
37 changes: 17 additions & 20 deletions index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import qs from 'qs';
import * as Core from './core';
import * as Pagination from './pagination';
import * as API from './resources';
import * as Errors from '~/error';
import type { Agent } from 'http';
import * as FileFromPath from 'formdata-node/file-from-path';

Expand Down Expand Up @@ -97,36 +98,32 @@ export class Lithic extends Core.APIClient {
return { arrayFormat: 'comma' };
}

static APIError = Core.APIError;

static APIConnectionError = Core.APIConnectionError;
static APIConnectionTimeoutError = Core.APIConnectionTimeoutError;

static BadRequestError = Core.BadRequestError;
static AuthenticationError = Core.AuthenticationError;
static PermissionDeniedError = Core.PermissionDeniedError;
static NotFoundError = Core.NotFoundError;
static ConflictError = Core.ConflictError;
static UnprocessableEntityError = Core.UnprocessableEntityError;
static RateLimitError = Core.RateLimitError;
static InternalServerError = Core.InternalServerError;
static APIError = Errors.APIError;
static APIConnectionError = Errors.APIConnectionError;
static APIConnectionTimeoutError = Errors.APIConnectionTimeoutError;
static NotFoundError = Errors.NotFoundError;
static ConflictError = Errors.ConflictError;
static RateLimitError = Errors.RateLimitError;
static BadRequestError = Errors.BadRequestError;
static AuthenticationError = Errors.AuthenticationError;
static InternalServerError = Errors.InternalServerError;
static PermissionDeniedError = Errors.PermissionDeniedError;
static UnprocessableEntityError = Errors.UnprocessableEntityError;
}

export const {
APIError,

APIConnectionError,
APIConnectionTimeoutError,

BadRequestError,
AuthenticationError,
PermissionDeniedError,
NotFoundError,
ConflictError,
UnprocessableEntityError,
RateLimitError,
BadRequestError,
AuthenticationError,
InternalServerError,
} = Lithic;
PermissionDeniedError,
UnprocessableEntityError,
} = Errors;

export import fileFromPath = FileFromPath.fileFromPath;

Expand Down
3 changes: 2 additions & 1 deletion resources/disputes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -380,7 +380,8 @@ export interface DisputeEvidence {
download_url?: string;

/**
* File name of evidence.
* File name of evidence. Recommended to give the dispute evidence a human-readable
* identifier.
*/
filename?: string;

Expand Down
25 changes: 16 additions & 9 deletions streaming.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,19 +102,26 @@ export class Stream<Item> implements AsyncIterable<Item>, APIResponse<Stream<Ite
const sse = this.decoder.decode(line);
if (sse) yield sse;
}

this.controller.abort();
}

async *[Symbol.asyncIterator](): AsyncIterator<Item, any, undefined> {
for await (const sse of this.iterMessages()) {
try {
yield JSON.parse(sse.data);
} catch (e) {
console.error(`Could not parse message into JSON:`, sse.data);
console.error(`From chunk:`, sse.raw);
throw e;
try {
for await (const sse of this.iterMessages()) {
try {
yield JSON.parse(sse.data);
} catch (e) {
console.error(`Could not parse message into JSON:`, sse.data);
console.error(`From chunk:`, sse.raw);
throw e;
}
}
} catch (e) {
// If the user calls `stream.controller.abort()`, we should exit without throwing.
if (e instanceof Error && e.name === 'AbortError') return;
throw e;
} finally {
// If the user `break`s, abort the ongoing request.
this.controller.abort();
}
}
}
Expand Down