kopia lustrzana https://github.com/transitive-bullshit/chatgpt-api
feat: add ChatGPTError with more info on HTTP errors
rodzic
8cc642e9bb
commit
90c6e3500f
|
@ -1,6 +1,7 @@
|
|||
import test from 'ava'
|
||||
import dotenv from 'dotenv-safe'
|
||||
|
||||
import * as types from './types'
|
||||
import { ChatGPTAPI } from './chatgpt-api'
|
||||
|
||||
dotenv.config()
|
||||
|
@ -20,6 +21,7 @@ test('ChatGPTAPI invalid session token', async (t) => {
|
|||
await chatgpt.ensureAuth()
|
||||
},
|
||||
{
|
||||
instanceOf: types.ChatGPTError,
|
||||
message: 'ChatGPT failed to refresh auth token. Error: Unauthorized'
|
||||
}
|
||||
)
|
||||
|
@ -64,6 +66,7 @@ if (!isCI) {
|
|||
await chatgpt.ensureAuth()
|
||||
},
|
||||
{
|
||||
instanceOf: types.ChatGPTError,
|
||||
message:
|
||||
'ChatGPT failed to refresh auth token. Error: session token may have expired'
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
import ExpiryMap from 'expiry-map'
|
||||
import pTimeout, { TimeoutError } from 'p-timeout'
|
||||
import pTimeout from 'p-timeout'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
|
||||
import * as types from './types'
|
||||
|
@ -68,7 +68,7 @@ export class ChatGPTAPI {
|
|||
this._accessTokenCache = new ExpiryMap<string, string>(accessTokenTTL)
|
||||
|
||||
if (!this._sessionToken) {
|
||||
throw new Error('ChatGPT invalid session token')
|
||||
throw new types.ChatGPTError('ChatGPT invalid session token')
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -238,6 +238,7 @@ export class ChatGPTAPI {
|
|||
return cachedAccessToken
|
||||
}
|
||||
|
||||
let response: Response
|
||||
try {
|
||||
const res = await fetch('https://chat.openai.com/api/auth/session', {
|
||||
headers: {
|
||||
|
@ -245,8 +246,14 @@ export class ChatGPTAPI {
|
|||
'user-agent': this._userAgent
|
||||
}
|
||||
}).then((r) => {
|
||||
response = r
|
||||
|
||||
if (!r.ok) {
|
||||
throw new Error(`${r.status} ${r.statusText}`)
|
||||
const error = new types.ChatGPTError(`${r.status} ${r.statusText}`)
|
||||
error.response = r
|
||||
error.statusCode = r.status
|
||||
error.statusText = r.statusText
|
||||
throw error
|
||||
}
|
||||
|
||||
return r.json() as any as types.SessionResult
|
||||
|
@ -255,22 +262,41 @@ export class ChatGPTAPI {
|
|||
const accessToken = res?.accessToken
|
||||
|
||||
if (!accessToken) {
|
||||
throw new Error('Unauthorized')
|
||||
const error = new types.ChatGPTError('Unauthorized')
|
||||
error.response = response
|
||||
error.statusCode = response?.status
|
||||
error.statusText = response?.statusText
|
||||
throw error
|
||||
}
|
||||
|
||||
const error = res?.error
|
||||
if (error) {
|
||||
if (error === 'RefreshAccessTokenError') {
|
||||
throw new Error('session token may have expired')
|
||||
const appError = res?.error
|
||||
if (appError) {
|
||||
if (appError === 'RefreshAccessTokenError') {
|
||||
const error = new types.ChatGPTError('session token may have expired')
|
||||
error.response = response
|
||||
error.statusCode = response?.status
|
||||
error.statusText = response?.statusText
|
||||
throw error
|
||||
} else {
|
||||
throw new Error(error)
|
||||
const error = new types.ChatGPTError(appError)
|
||||
error.response = response
|
||||
error.statusCode = response?.status
|
||||
error.statusText = response?.statusText
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
this._accessTokenCache.set(KEY_ACCESS_TOKEN, accessToken)
|
||||
return accessToken
|
||||
} catch (err: any) {
|
||||
throw new Error(`ChatGPT failed to refresh auth token. ${err.toString()}`)
|
||||
const error = new types.ChatGPTError(
|
||||
`ChatGPT failed to refresh auth token. ${err.toString()}`
|
||||
)
|
||||
error.response = response
|
||||
error.statusCode = response?.status
|
||||
error.statusText = response?.statusText
|
||||
error.originalError = err
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { createParser } from 'eventsource-parser'
|
||||
|
||||
import * as types from './types'
|
||||
import { fetch } from './fetch'
|
||||
import { streamAsyncIterable } from './stream-async-iterable'
|
||||
|
||||
|
@ -10,7 +11,12 @@ export async function fetchSSE(
|
|||
const { onMessage, ...fetchOptions } = options
|
||||
const res = await fetch(url, fetchOptions)
|
||||
if (!res.ok) {
|
||||
throw new Error(`ChatGPTAPI error ${res.status || res.statusText}`)
|
||||
const msg = `ChatGPTAPI error ${res.status || res.statusText}`
|
||||
const error = new types.ChatGPTError(msg)
|
||||
error.statusCode = res.status
|
||||
error.statusText = res.statusText
|
||||
error.response = res
|
||||
throw error
|
||||
}
|
||||
|
||||
const parser = createParser((event) => {
|
||||
|
@ -25,7 +31,7 @@ export async function fetchSSE(
|
|||
const body: NodeJS.ReadableStream = res.body as any
|
||||
|
||||
if (!body.on || !body.read) {
|
||||
throw new Error('unsupported "fetch" implementation')
|
||||
throw new types.ChatGPTError('unsupported "fetch" implementation')
|
||||
}
|
||||
|
||||
body.on('readable', () => {
|
||||
|
|
|
@ -287,3 +287,10 @@ export type SendConversationMessageOptions = Omit<
|
|||
SendMessageOptions,
|
||||
'conversationId' | 'parentMessageId'
|
||||
>
|
||||
|
||||
export class ChatGPTError extends Error {
|
||||
statusCode?: number
|
||||
statusText?: string
|
||||
response?: Response
|
||||
originalError?: Error
|
||||
}
|
||||
|
|
Ładowanie…
Reference in New Issue