UNPKG

siliconflow-serverless-client

Version:

![@siliconflow/siliconflow-js npm package](https://img.shields.io/npm/v/@siliconflow/siliconflow-js?color=%25237527D7&label=@siliconflow/siliconflow-js&style=flat-square)

308 lines (284 loc) 8.8 kB
import { dispatchRequest } from "./request"; import { storageImpl } from "./storage"; import { EnqueueResult, QueueStatus } from "./types"; import { ensureAppIdFormat, isUUIDv4, isValidUrl } from "./utils"; /** * The function input and other configuration when running * the function, such as the HTTP method to use. */ type RunOptions<Input> = { /** * The path to the function, if any. Defaults to ``. * @deprecated Pass the path as part of the app id itself, e.g. */ readonly path?: string; /** * The function input. It will be submitted either as query params * or the body payload, depending on the `method`. */ readonly input?: Input; /** * The HTTP method, defaults to `post`; */ readonly method?: "get" | "post" | "put" | "delete" | string; /** * If `true`, the function will automatically upload any files * (i.e. instances of `Blob`) or data:uri in the input. * * You can disable this behavior by setting it to `false`, which * is useful in cases where you want to upload the files yourself * or use small data:uri in the input. */ readonly autoUpload?: boolean; }; type ExtraOptions = { /** * If `true`, the function will use the queue to run the function * asynchronously and return the result in a separate call. This * influences how the URL is built. */ readonly subdomain?: string; }; /** * Builds the final url to run the function based on its `id` or alias and * a the options from `RunOptions<Input>`. * * @private * @param id the function id or alias * @param options the run options * @returns the final url to run the function */ export function buildUrl<Input>( id: string, options: RunOptions<Input> & ExtraOptions = {}, ): string { const method = (options.method ?? "post").toLowerCase(); const path = (options.path ?? "").replace(/^\//, "").replace(/\/{2,}/, "/"); const input = options.input; const params = // eslint-disable-next-line @typescript-eslint/no-explicit-any method === "get" && input ? new URLSearchParams(input as any) : undefined; const queryParams = params ? `?${params.toString()}` : ""; const parts = id.split("/"); if (isValidUrl(id)) { const url = id.endsWith("/") ? id : `${id}/`; return `${url}${path}${queryParams}`; } const appId = ensureAppIdFormat(id); // const subdomain = options.subdomain ? `${options.subdomain}.` : ''; const subdomain = process.env.NEXT_PUBLIC_API_DOMAIN; const url = `${subdomain}/${appId}/${path}`; // console.log("url", url); return `${url.replace(/\/$/, "")}${queryParams}`; } export async function send<Input, Output>( id: string, options: RunOptions<Input> & ExtraOptions = {}, ): Promise<Output> { const input = options.input; // options.input && options.autoUpload !== false // ? await storageImpl.transformInput(options.input) // : options.input; return dispatchRequest<Input, Output>( options.method ?? "post", buildUrl(id, options), input as Input, ); } /** * * @param id the registered function revision id or alias. * @returns the remote function output */ export async function run<Input, Output>( id: string, options: RunOptions<Input> = {}, ): Promise<Output> { return send(id, options); } /** * 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, logs: options.logs ?? false, }); 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. */ type QueueSubscribeOptions = { /** * The interval (in milliseconds) at which to poll for updates. * If not provided, a default value of `1000` will be used. */ pollInterval?: number; /** * Callback function that is called when a request is enqueued. * @param requestId - The unique identifier for the enqueued request. */ onEnqueue?: (requestId: string) => void; /** * Callback function that is called when the status of the queue changes. * @param status - The current status of the queue. */ onQueueUpdate?: (status: QueueStatus) => void; /** * If `true`, the response will include the logs for the request. * Defaults to `false`. */ logs?: boolean; }; /** * Options for submitting a request to the queue. */ type SubmitOptions<Input> = RunOptions<Input> & { /** * The URL to send a webhook notification to when the request is completed. * @see WebHookResponse */ webhookUrl?: string; }; type BaseQueueOptions = { /** * The unique identifier for the enqueued request. */ requestId: string; }; type QueueStatusOptions = BaseQueueOptions & { /** * If `true`, the response will include the logs for the request. * Defaults to `false`. */ logs?: boolean; }; /** * Represents a request queue with methods for submitting requests, * checking their status, retrieving results, and subscribing to updates. */ interface Queue { /** * Submits a request to the queue. * * @param id - The ID or URL of the function web endpoint. * @param options - Options to configure how the request is run. * @returns A promise that resolves to the result of enqueuing the request. */ submit<Input>( id: string, options: SubmitOptions<Input>, ): Promise<EnqueueResult>; /** * Retrieves the status of 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. * @returns A promise that resolves to the status of the request. */ status(id: string, options: QueueStatusOptions): Promise<QueueStatus>; /** * Retrieves the result of a specific request from the queue. * * @param id - The ID or URL of the function web endpoint. * @param options - Options to configure how the request is run. * @returns A promise that resolves to the result of the request. */ result<Output>(id: string, options: BaseQueueOptions): Promise<Output>; /** * @deprecated */ subscribe<Input, Output>( id: string, options: RunOptions<Input> & QueueSubscribeOptions, ): Promise<Output>; } /** * The siliconflow run queue module. It allows to submit a function to the queue and get its result * on a separate call. This is useful for long running functions that can be executed * asynchronously and not . */ export const queue: Queue = { async submit<Input>( id: string, options: SubmitOptions<Input>, ): Promise<EnqueueResult> { const { webhookUrl, path = "", ...runOptions } = options; const query = webhookUrl ? "?" + new URLSearchParams({ fal_webhook: webhookUrl }).toString() : ""; return send(id, { ...runOptions, subdomain: "queue", method: "post", path: path + query, }); }, async status( id: string, { requestId, logs = false }: QueueStatusOptions, ): Promise<QueueStatus> { const [appOwner, appAlias] = ensureAppIdFormat(id).split("/"); return send(`${appOwner}/${appAlias}`, { subdomain: "queue", method: "get", path: `/requests/${requestId}/status`, input: { logs: logs ? "1" : "0", }, }); }, async result<Output>( id: string, { requestId }: BaseQueueOptions, ): Promise<Output> { const [appOwner, appAlias] = ensureAppIdFormat(id).split("/"); return send(`${appOwner}/${appAlias}`, { subdomain: "queue", method: "get", path: `/requests/${requestId}`, }); }, subscribe, };