diff --git a/libs/client/src/function.ts b/libs/client/src/function.ts
index 2332898..eae9781 100644
--- a/libs/client/src/function.ts
+++ b/libs/client/src/function.ts
@@ -112,6 +112,50 @@ export async function run (
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 (
+ id: string,
+ options: RunOptions & QueueSubscribeOptions = {}
+): Promise {
+ const { request_id: requestId } = await queue.submit(id, options);
+ if (options.onEnqueue) {
+ options.onEnqueue(requestId);
+ }
+ return new Promise((resolve, reject) => {
+ let timeoutId: ReturnType;
+ 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(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.
*/
@@ -168,11 +212,7 @@ interface Queue {
result(id: string, requestId: string): Promise;
/**
- * 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.
+ * @deprecated Use `fal.subscribe` instead.
*/
subscribe (
id: string,
@@ -204,40 +244,5 @@ export const queue: Queue = {
path: `/fal/queue/requests/${requestId}/response`,
});
},
- async subscribe (
- id: string,
- options: RunOptions & QueueSubscribeOptions = {}
- ): Promise {
- const { request_id: requestId } = await queue.submit(id, options);
- if (options.onEnqueue) {
- options.onEnqueue(requestId);
- }
- return new Promise((resolve, reject) => {
- let timeoutId: ReturnType;
- 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(id, requestId);
- resolve(result);
- } catch (error) {
- reject(error);
- }
- return;
- }
- timeoutId = setTimeout(poll, pollInterval);
- } catch (error) {
- clearTimeout(timeoutId);
- reject(error);
- }
- };
- poll().catch(reject);
- });
- },
+ subscribe,
};
diff --git a/libs/client/src/index.ts b/libs/client/src/index.ts
index b3df91b..c94b8c0 100644
--- a/libs/client/src/index.ts
+++ b/libs/client/src/index.ts
@@ -1,6 +1,7 @@
export { config, getConfig } from './config';
-export { queue, run } from './function';
+export { queue, run, subscribe } from './function';
export { withMiddleware } from './middleware';
+export { ApiError, ValidationError } from './response';
export type { RequestMiddleware } from './middleware';
export type { ResponseHandler } from './response';
export type { QueueStatus } from './types';
diff --git a/libs/client/src/response.ts b/libs/client/src/response.ts
index b0ee0c7..cf9cf6b 100644
--- a/libs/client/src/response.ts
+++ b/libs/client/src/response.ts
@@ -1,14 +1,17 @@
+import { ValidationErrorInfo } from './types';
+
export type ResponseHandler = (response: Response) => Promise;
type ApiErrorArgs = {
message: string;
status: number;
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
body?: any;
};
-export class ApiError extends Error {
+export class ApiError extends Error {
public readonly status: number;
- public readonly body?: any;
+ public readonly body: Body;
constructor({ message, status, body }: ApiErrorArgs) {
super(message);
this.name = 'ApiError';
@@ -17,6 +20,13 @@ export class ApiError extends Error {
}
}
+export class ValidationError extends ApiError {
+ constructor(args: ApiErrorArgs) {
+ super(args);
+ this.name = 'ValidationError';
+ }
+}
+
export async function defaultResponseHandler(
response: Response
): Promise {
@@ -25,13 +35,14 @@ export async function defaultResponseHandler(
if (!response.ok) {
if (contentType?.includes('application/json')) {
const body = await response.json();
- throw new ApiError({
+ const ErrorType = status === 422 ? ValidationError : ApiError;
+ throw new ErrorType({
message: body.message || statusText,
status,
body,
});
}
- throw new Error(`HTTP ${status}: ${statusText}`);
+ throw new ApiError({ message: `HTTP ${status}: ${statusText}`, status });
}
if (contentType?.includes('application/json')) {
return response.json() as Promise;
diff --git a/libs/client/src/types.ts b/libs/client/src/types.ts
index 258c8e2..74ad756 100644
--- a/libs/client/src/types.ts
+++ b/libs/client/src/types.ts
@@ -33,3 +33,9 @@ export type QueueStatus =
export function isQueueStatus(obj: any): obj is QueueStatus {
return obj && obj.status && obj.response_url;
}
+
+export type ValidationErrorInfo = {
+ msg: string;
+ loc: Array;
+ type: string;
+};