diff --git a/apps/demo-nextjs-app-router/app/camera-turbo/page.tsx b/apps/demo-nextjs-app-router/app/camera-turbo/page.tsx index 716b400..9f05f74 100644 --- a/apps/demo-nextjs-app-router/app/camera-turbo/page.tsx +++ b/apps/demo-nextjs-app-router/app/camera-turbo/page.tsx @@ -137,7 +137,7 @@ export default function WebcamPage() { const previewRef = useRef(null); const { send } = fal.realtime.connect( - 'fal-ai/sd-turbo-real-time-high-fps-msgpack', + 'fal-ai/sd-turbo-real-time-high-fps-msgpack-a10g', { connectionKey: 'camera-turbo-demo', // not throttling the client, handling throttling of the camera itself diff --git a/apps/demo-nextjs-app-router/app/page.tsx b/apps/demo-nextjs-app-router/app/page.tsx index 4d9e53a..bfc74eb 100644 --- a/apps/demo-nextjs-app-router/app/page.tsx +++ b/apps/demo-nextjs-app-router/app/page.tsx @@ -79,27 +79,24 @@ export default function Home() { setLoading(true); const start = Date.now(); try { - const result: Result = await fal.subscribe( - '54285744/illusion-diffusion', - { - input: { - prompt, - image_url: imageFile, - image_size: 'square_hd', - }, - pollInterval: 5000, // Default is 1000 (every 1s) - logs: true, - onQueueUpdate(update) { - setElapsedTime(Date.now() - start); - if ( - update.status === 'IN_PROGRESS' || - update.status === 'COMPLETED' - ) { - setLogs((update.logs || []).map((log) => log.message)); - } - }, - } - ); + const result: Result = await fal.subscribe('fal-ai/illusion-diffusion', { + input: { + prompt, + image_url: imageFile, + image_size: 'square_hd', + }, + pollInterval: 3000, // Default is 1000 (every 1s) + logs: true, + onQueueUpdate(update) { + setElapsedTime(Date.now() - start); + if ( + update.status === 'IN_PROGRESS' || + update.status === 'COMPLETED' + ) { + setLogs((update.logs || []).map((log) => log.message)); + } + }, + }); setResult(result); } catch (error: any) { setError(error); diff --git a/libs/client/package.json b/libs/client/package.json index 8d1f95e..585b5da 100644 --- a/libs/client/package.json +++ b/libs/client/package.json @@ -1,7 +1,7 @@ { "name": "@fal-ai/serverless-client", "description": "The fal serverless JS/TS client", - "version": "0.8.3", + "version": "0.8.4", "license": "MIT", "repository": { "type": "git", diff --git a/libs/client/src/function.ts b/libs/client/src/function.ts index f354ba6..8603e9a 100644 --- a/libs/client/src/function.ts +++ b/libs/client/src/function.ts @@ -10,6 +10,7 @@ import { ensureAppIdFormat, isUUIDv4, isValidUrl } from './utils'; type RunOptions = { /** * The path to the function, if any. Defaults to ``. + * @deprecated Pass the path as part of the app id itself, e.g. `fal-ai/sdxl/image-to-image` */ readonly path?: string; @@ -268,11 +269,12 @@ export const queue: Queue = { id: string, options: SubmitOptions ): Promise { + const [appOwner, appAlias] = ensureAppIdFormat(id).split('/'); const { webhookUrl, path = '', ...runOptions } = options; const query = webhookUrl ? '?' + new URLSearchParams({ fal_webhook: webhookUrl }).toString() : ''; - return send(id, { + return send(`${appOwner}/${appAlias}`, { ...runOptions, subdomain: 'queue', method: 'post', @@ -283,7 +285,8 @@ export const queue: Queue = { id: string, { requestId, logs = false }: QueueStatusOptions ): Promise { - return send(id, { + const [appOwner, appAlias] = ensureAppIdFormat(id).split('/'); + return send(`${appOwner}/${appAlias}`, { subdomain: 'queue', method: 'get', path: `/requests/${requestId}/status`, @@ -296,7 +299,8 @@ export const queue: Queue = { id: string, { requestId }: BaseQueueOptions ): Promise { - return send(id, { + const [appOwner, appAlias] = ensureAppIdFormat(id).split('/'); + return send(`${appOwner}/${appAlias}`, { subdomain: 'queue', method: 'get', path: `/requests/${requestId}`, diff --git a/libs/client/src/realtime.ts b/libs/client/src/realtime.ts index 2c3f465..07eda66 100644 --- a/libs/client/src/realtime.ts +++ b/libs/client/src/realtime.ts @@ -249,6 +249,17 @@ type RealtimeUrlParams = { maxBuffering?: number; }; +// This is a list of apps deployed before formal realtime support. Their URLs follow +// a different pattern and will be kept here until we fully sunset them. +const LEGACY_APPS = [ + 'lcm-sd15-i2i', + 'lcm', + 'sdxl-turbo-realtime', + 'sd-turbo-real-time-high-fps-msgpack-a10g', + 'lcm-plexed-sd15-i2i', + 'sd-turbo-real-time-high-fps-msgpack', +]; + function buildRealtimeUrl( app: string, { token, maxBuffering }: RealtimeUrlParams @@ -263,7 +274,10 @@ function buildRealtimeUrl( queryParams.set('max_buffering', maxBuffering.toFixed(0)); } const appId = ensureAppIdFormat(app); - return `wss://fal.run/${appId}/ws?${queryParams.toString()}`; + const [, appAlias] = ensureAppIdFormat(app).split('/'); + const suffix = + LEGACY_APPS.includes(appAlias) || !app.includes('/') ? 'ws' : 'realtime'; + return `wss://fal.run/${appId}/${suffix}?${queryParams.toString()}`; } const TOKEN_EXPIRATION_SECONDS = 120; diff --git a/libs/client/src/utils.spec.ts b/libs/client/src/utils.spec.ts index e995936..443a11e 100644 --- a/libs/client/src/utils.spec.ts +++ b/libs/client/src/utils.spec.ts @@ -22,6 +22,11 @@ describe('The utils test suite', () => { expect(ensureAppIdFormat(id)).toBe(id); }); + it('shoud match a current appOwner/appId/path format', () => { + const id = 'fal-ai/fast-sdxl/image-to-image'; + expect(ensureAppIdFormat(id)).toBe(id); + }); + it('should throw on an invalid app id format', () => { const id = 'just-an-id'; expect(() => ensureAppIdFormat(id)).toThrowError(); diff --git a/libs/client/src/utils.ts b/libs/client/src/utils.ts index 750a584..5de1198 100644 --- a/libs/client/src/utils.ts +++ b/libs/client/src/utils.ts @@ -9,7 +9,7 @@ export function isUUIDv4(id: string): boolean { export function ensureAppIdFormat(id: string): string { const parts = id.split('/'); - if (parts.length === 2) { + if (parts.length > 1) { return id; } const [, appOwner, appId] = /^([0-9]+)-([a-zA-Z0-9-]+)$/.exec(id) || [];