feat: validation error type (#13)
* feat: add validation error type * feat: move subscribe to top-level * fix: wrong import
This commit is contained in:
parent
25a763602f
commit
f240e622d3
@ -112,6 +112,50 @@ export async function run<Input, Output>(
|
|||||||
return await responseHandler(response);
|
return await responseHandler(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subscribes to updates for a specific request in the queue.
|
||||||
|
*
|
||||||
|
* @param id - The ID or URL of the function web endpoint.
|
||||||
|
* @param options - Options to configure how the request is run and how updates are received.
|
||||||
|
* @returns A promise that resolves to the result of the request once it's completed.
|
||||||
|
*/
|
||||||
|
export async function subscribe<Input, Output>(
|
||||||
|
id: string,
|
||||||
|
options: RunOptions<Input> & QueueSubscribeOptions = {}
|
||||||
|
): Promise<Output> {
|
||||||
|
const { request_id: requestId } = await queue.submit(id, options);
|
||||||
|
if (options.onEnqueue) {
|
||||||
|
options.onEnqueue(requestId);
|
||||||
|
}
|
||||||
|
return new Promise<Output>((resolve, reject) => {
|
||||||
|
let timeoutId: ReturnType<typeof setTimeout>;
|
||||||
|
const pollInterval = options.pollInterval ?? 1000;
|
||||||
|
const poll = async () => {
|
||||||
|
try {
|
||||||
|
const requestStatus = await queue.status(id, requestId);
|
||||||
|
if (options.onQueueUpdate) {
|
||||||
|
options.onQueueUpdate(requestStatus);
|
||||||
|
}
|
||||||
|
if (requestStatus.status === 'COMPLETED') {
|
||||||
|
clearTimeout(timeoutId);
|
||||||
|
try {
|
||||||
|
const result = await queue.result<Output>(id, requestId);
|
||||||
|
resolve(result);
|
||||||
|
} catch (error) {
|
||||||
|
reject(error);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
timeoutId = setTimeout(poll, pollInterval);
|
||||||
|
} catch (error) {
|
||||||
|
clearTimeout(timeoutId);
|
||||||
|
reject(error);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
poll().catch(reject);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Options for subscribing to the request queue.
|
* Options for subscribing to the request queue.
|
||||||
*/
|
*/
|
||||||
@ -168,11 +212,7 @@ interface Queue {
|
|||||||
result<Output>(id: string, requestId: string): Promise<Output>;
|
result<Output>(id: string, requestId: string): Promise<Output>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Subscribes to updates for a specific request in the queue.
|
* @deprecated Use `fal.subscribe` instead.
|
||||||
*
|
|
||||||
* @param id - The ID or URL of the function web endpoint.
|
|
||||||
* @param options - Options to configure how the request is run and how updates are received.
|
|
||||||
* @returns A promise that resolves to the result of the request once it's completed.
|
|
||||||
*/
|
*/
|
||||||
subscribe<Input, Output>(
|
subscribe<Input, Output>(
|
||||||
id: string,
|
id: string,
|
||||||
@ -204,40 +244,5 @@ export const queue: Queue = {
|
|||||||
path: `/fal/queue/requests/${requestId}/response`,
|
path: `/fal/queue/requests/${requestId}/response`,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
async subscribe<Input, Output>(
|
subscribe,
|
||||||
id: string,
|
|
||||||
options: RunOptions<Input> & QueueSubscribeOptions = {}
|
|
||||||
): Promise<Output> {
|
|
||||||
const { request_id: requestId } = await queue.submit(id, options);
|
|
||||||
if (options.onEnqueue) {
|
|
||||||
options.onEnqueue(requestId);
|
|
||||||
}
|
|
||||||
return new Promise<Output>((resolve, reject) => {
|
|
||||||
let timeoutId: ReturnType<typeof setTimeout>;
|
|
||||||
const pollInterval = options.pollInterval ?? 1000;
|
|
||||||
const poll = async () => {
|
|
||||||
try {
|
|
||||||
const requestStatus = await queue.status(id, requestId);
|
|
||||||
if (options.onQueueUpdate) {
|
|
||||||
options.onQueueUpdate(requestStatus);
|
|
||||||
}
|
|
||||||
if (requestStatus.status === 'COMPLETED') {
|
|
||||||
clearTimeout(timeoutId);
|
|
||||||
try {
|
|
||||||
const result = await queue.result<Output>(id, requestId);
|
|
||||||
resolve(result);
|
|
||||||
} catch (error) {
|
|
||||||
reject(error);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
timeoutId = setTimeout(poll, pollInterval);
|
|
||||||
} catch (error) {
|
|
||||||
clearTimeout(timeoutId);
|
|
||||||
reject(error);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
poll().catch(reject);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
export { config, getConfig } from './config';
|
export { config, getConfig } from './config';
|
||||||
export { queue, run } from './function';
|
export { queue, run, subscribe } from './function';
|
||||||
export { withMiddleware } from './middleware';
|
export { withMiddleware } from './middleware';
|
||||||
|
export { ApiError, ValidationError } from './response';
|
||||||
export type { RequestMiddleware } from './middleware';
|
export type { RequestMiddleware } from './middleware';
|
||||||
export type { ResponseHandler } from './response';
|
export type { ResponseHandler } from './response';
|
||||||
export type { QueueStatus } from './types';
|
export type { QueueStatus } from './types';
|
||||||
|
|||||||
@ -1,14 +1,17 @@
|
|||||||
|
import { ValidationErrorInfo } from './types';
|
||||||
|
|
||||||
export type ResponseHandler<Output> = (response: Response) => Promise<Output>;
|
export type ResponseHandler<Output> = (response: Response) => Promise<Output>;
|
||||||
|
|
||||||
type ApiErrorArgs = {
|
type ApiErrorArgs = {
|
||||||
message: string;
|
message: string;
|
||||||
status: number;
|
status: number;
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
body?: any;
|
body?: any;
|
||||||
};
|
};
|
||||||
|
|
||||||
export class ApiError extends Error {
|
export class ApiError<Body> extends Error {
|
||||||
public readonly status: number;
|
public readonly status: number;
|
||||||
public readonly body?: any;
|
public readonly body: Body;
|
||||||
constructor({ message, status, body }: ApiErrorArgs) {
|
constructor({ message, status, body }: ApiErrorArgs) {
|
||||||
super(message);
|
super(message);
|
||||||
this.name = 'ApiError';
|
this.name = 'ApiError';
|
||||||
@ -17,6 +20,13 @@ export class ApiError extends Error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class ValidationError extends ApiError<ValidationErrorInfo[]> {
|
||||||
|
constructor(args: ApiErrorArgs) {
|
||||||
|
super(args);
|
||||||
|
this.name = 'ValidationError';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export async function defaultResponseHandler<Output>(
|
export async function defaultResponseHandler<Output>(
|
||||||
response: Response
|
response: Response
|
||||||
): Promise<Output> {
|
): Promise<Output> {
|
||||||
@ -25,13 +35,14 @@ export async function defaultResponseHandler<Output>(
|
|||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
if (contentType?.includes('application/json')) {
|
if (contentType?.includes('application/json')) {
|
||||||
const body = await response.json();
|
const body = await response.json();
|
||||||
throw new ApiError({
|
const ErrorType = status === 422 ? ValidationError : ApiError;
|
||||||
|
throw new ErrorType({
|
||||||
message: body.message || statusText,
|
message: body.message || statusText,
|
||||||
status,
|
status,
|
||||||
body,
|
body,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
throw new Error(`HTTP ${status}: ${statusText}`);
|
throw new ApiError({ message: `HTTP ${status}: ${statusText}`, status });
|
||||||
}
|
}
|
||||||
if (contentType?.includes('application/json')) {
|
if (contentType?.includes('application/json')) {
|
||||||
return response.json() as Promise<Output>;
|
return response.json() as Promise<Output>;
|
||||||
|
|||||||
@ -33,3 +33,9 @@ export type QueueStatus =
|
|||||||
export function isQueueStatus(obj: any): obj is QueueStatus {
|
export function isQueueStatus(obj: any): obj is QueueStatus {
|
||||||
return obj && obj.status && obj.response_url;
|
return obj && obj.status && obj.response_url;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type ValidationErrorInfo = {
|
||||||
|
msg: string;
|
||||||
|
loc: Array<string | number>;
|
||||||
|
type: string;
|
||||||
|
};
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user