feat(client): app id with path + realtime url (#51)
* feat: app id + path format support * chore: bump client to 0.8.4
This commit is contained in:
parent
66d817b2a6
commit
e0b7627f7a
@ -137,7 +137,7 @@ export default function WebcamPage() {
|
|||||||
const previewRef = useRef<HTMLCanvasElement | null>(null);
|
const previewRef = useRef<HTMLCanvasElement | null>(null);
|
||||||
|
|
||||||
const { send } = fal.realtime.connect<LCMInput, LCMOutput>(
|
const { send } = fal.realtime.connect<LCMInput, LCMOutput>(
|
||||||
'fal-ai/sd-turbo-real-time-high-fps-msgpack',
|
'fal-ai/sd-turbo-real-time-high-fps-msgpack-a10g',
|
||||||
{
|
{
|
||||||
connectionKey: 'camera-turbo-demo',
|
connectionKey: 'camera-turbo-demo',
|
||||||
// not throttling the client, handling throttling of the camera itself
|
// not throttling the client, handling throttling of the camera itself
|
||||||
|
|||||||
@ -79,15 +79,13 @@ export default function Home() {
|
|||||||
setLoading(true);
|
setLoading(true);
|
||||||
const start = Date.now();
|
const start = Date.now();
|
||||||
try {
|
try {
|
||||||
const result: Result = await fal.subscribe(
|
const result: Result = await fal.subscribe('fal-ai/illusion-diffusion', {
|
||||||
'54285744/illusion-diffusion',
|
|
||||||
{
|
|
||||||
input: {
|
input: {
|
||||||
prompt,
|
prompt,
|
||||||
image_url: imageFile,
|
image_url: imageFile,
|
||||||
image_size: 'square_hd',
|
image_size: 'square_hd',
|
||||||
},
|
},
|
||||||
pollInterval: 5000, // Default is 1000 (every 1s)
|
pollInterval: 3000, // Default is 1000 (every 1s)
|
||||||
logs: true,
|
logs: true,
|
||||||
onQueueUpdate(update) {
|
onQueueUpdate(update) {
|
||||||
setElapsedTime(Date.now() - start);
|
setElapsedTime(Date.now() - start);
|
||||||
@ -98,8 +96,7 @@ export default function Home() {
|
|||||||
setLogs((update.logs || []).map((log) => log.message));
|
setLogs((update.logs || []).map((log) => log.message));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
});
|
||||||
);
|
|
||||||
setResult(result);
|
setResult(result);
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
setError(error);
|
setError(error);
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@fal-ai/serverless-client",
|
"name": "@fal-ai/serverless-client",
|
||||||
"description": "The fal serverless JS/TS client",
|
"description": "The fal serverless JS/TS client",
|
||||||
"version": "0.8.3",
|
"version": "0.8.4",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import { ensureAppIdFormat, isUUIDv4, isValidUrl } from './utils';
|
|||||||
type RunOptions<Input> = {
|
type RunOptions<Input> = {
|
||||||
/**
|
/**
|
||||||
* The path to the function, if any. Defaults to ``.
|
* 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;
|
readonly path?: string;
|
||||||
|
|
||||||
@ -268,11 +269,12 @@ export const queue: Queue = {
|
|||||||
id: string,
|
id: string,
|
||||||
options: SubmitOptions<Input>
|
options: SubmitOptions<Input>
|
||||||
): Promise<EnqueueResult> {
|
): Promise<EnqueueResult> {
|
||||||
|
const [appOwner, appAlias] = ensureAppIdFormat(id).split('/');
|
||||||
const { webhookUrl, path = '', ...runOptions } = options;
|
const { webhookUrl, path = '', ...runOptions } = options;
|
||||||
const query = webhookUrl
|
const query = webhookUrl
|
||||||
? '?' + new URLSearchParams({ fal_webhook: webhookUrl }).toString()
|
? '?' + new URLSearchParams({ fal_webhook: webhookUrl }).toString()
|
||||||
: '';
|
: '';
|
||||||
return send(id, {
|
return send(`${appOwner}/${appAlias}`, {
|
||||||
...runOptions,
|
...runOptions,
|
||||||
subdomain: 'queue',
|
subdomain: 'queue',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
@ -283,7 +285,8 @@ export const queue: Queue = {
|
|||||||
id: string,
|
id: string,
|
||||||
{ requestId, logs = false }: QueueStatusOptions
|
{ requestId, logs = false }: QueueStatusOptions
|
||||||
): Promise<QueueStatus> {
|
): Promise<QueueStatus> {
|
||||||
return send(id, {
|
const [appOwner, appAlias] = ensureAppIdFormat(id).split('/');
|
||||||
|
return send(`${appOwner}/${appAlias}`, {
|
||||||
subdomain: 'queue',
|
subdomain: 'queue',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
path: `/requests/${requestId}/status`,
|
path: `/requests/${requestId}/status`,
|
||||||
@ -296,7 +299,8 @@ export const queue: Queue = {
|
|||||||
id: string,
|
id: string,
|
||||||
{ requestId }: BaseQueueOptions
|
{ requestId }: BaseQueueOptions
|
||||||
): Promise<Output> {
|
): Promise<Output> {
|
||||||
return send(id, {
|
const [appOwner, appAlias] = ensureAppIdFormat(id).split('/');
|
||||||
|
return send(`${appOwner}/${appAlias}`, {
|
||||||
subdomain: 'queue',
|
subdomain: 'queue',
|
||||||
method: 'get',
|
method: 'get',
|
||||||
path: `/requests/${requestId}`,
|
path: `/requests/${requestId}`,
|
||||||
|
|||||||
@ -249,6 +249,17 @@ type RealtimeUrlParams = {
|
|||||||
maxBuffering?: number;
|
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(
|
function buildRealtimeUrl(
|
||||||
app: string,
|
app: string,
|
||||||
{ token, maxBuffering }: RealtimeUrlParams
|
{ token, maxBuffering }: RealtimeUrlParams
|
||||||
@ -263,7 +274,10 @@ function buildRealtimeUrl(
|
|||||||
queryParams.set('max_buffering', maxBuffering.toFixed(0));
|
queryParams.set('max_buffering', maxBuffering.toFixed(0));
|
||||||
}
|
}
|
||||||
const appId = ensureAppIdFormat(app);
|
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;
|
const TOKEN_EXPIRATION_SECONDS = 120;
|
||||||
|
|||||||
@ -22,6 +22,11 @@ describe('The utils test suite', () => {
|
|||||||
expect(ensureAppIdFormat(id)).toBe(id);
|
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', () => {
|
it('should throw on an invalid app id format', () => {
|
||||||
const id = 'just-an-id';
|
const id = 'just-an-id';
|
||||||
expect(() => ensureAppIdFormat(id)).toThrowError();
|
expect(() => ensureAppIdFormat(id)).toThrowError();
|
||||||
|
|||||||
@ -9,7 +9,7 @@ export function isUUIDv4(id: string): boolean {
|
|||||||
|
|
||||||
export function ensureAppIdFormat(id: string): string {
|
export function ensureAppIdFormat(id: string): string {
|
||||||
const parts = id.split('/');
|
const parts = id.split('/');
|
||||||
if (parts.length === 2) {
|
if (parts.length > 1) {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
const [, appOwner, appId] = /^([0-9]+)-([a-zA-Z0-9-]+)$/.exec(id) || [];
|
const [, appOwner, appId] = /^([0-9]+)-([a-zA-Z0-9-]+)$/.exec(id) || [];
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user