diff --git a/apps/demo-nextjs-app-router/app/comfy/image-to-image/page.tsx b/apps/demo-nextjs-app-router/app/comfy/image-to-image/page.tsx
index 1f349f3..6a4c4de 100644
--- a/apps/demo-nextjs-app-router/app/comfy/image-to-image/page.tsx
+++ b/apps/demo-nextjs-app-router/app/comfy/image-to-image/page.tsx
@@ -90,7 +90,6 @@ export default function ComfyImageToImagePage() {
prompt: prompt,
loadimage_1: imageFile,
},
- pollInterval: 3000, // Default is 1000 (every 1s)
logs: true,
onQueueUpdate(update) {
setElapsedTime(Date.now() - start);
diff --git a/apps/demo-nextjs-app-router/app/comfy/image-to-video/page.tsx b/apps/demo-nextjs-app-router/app/comfy/image-to-video/page.tsx
index 037fc3c..1baec15 100644
--- a/apps/demo-nextjs-app-router/app/comfy/image-to-video/page.tsx
+++ b/apps/demo-nextjs-app-router/app/comfy/image-to-video/page.tsx
@@ -85,7 +85,6 @@ export default function ComfyImageToVideoPage() {
input: {
loadimage_1: imageFile,
},
- pollInterval: 3000, // Default is 1000 (every 1s)
logs: true,
onQueueUpdate(update) {
setElapsedTime(Date.now() - start);
diff --git a/apps/demo-nextjs-app-router/app/comfy/text-to-image/page.tsx b/apps/demo-nextjs-app-router/app/comfy/text-to-image/page.tsx
index 45ccd30..b9d5d7f 100644
--- a/apps/demo-nextjs-app-router/app/comfy/text-to-image/page.tsx
+++ b/apps/demo-nextjs-app-router/app/comfy/text-to-image/page.tsx
@@ -86,7 +86,6 @@ export default function ComfyTextToImagePage() {
input: {
prompt: prompt,
},
- pollInterval: 3000, // Default is 1000 (every 1s)
logs: true,
onQueueUpdate(update) {
setElapsedTime(Date.now() - start);
diff --git a/apps/demo-nextjs-app-router/app/page.tsx b/apps/demo-nextjs-app-router/app/page.tsx
index bfc74eb..2fa1afd 100644
--- a/apps/demo-nextjs-app-router/app/page.tsx
+++ b/apps/demo-nextjs-app-router/app/page.tsx
@@ -85,7 +85,6 @@ export default function Home() {
image_url: imageFile,
image_size: 'square_hd',
},
- pollInterval: 3000, // Default is 1000 (every 1s)
logs: true,
onQueueUpdate(update) {
setElapsedTime(Date.now() - start);
diff --git a/apps/demo-nextjs-app-router/app/queue/page.tsx b/apps/demo-nextjs-app-router/app/queue/page.tsx
new file mode 100644
index 0000000..b8edc23
--- /dev/null
+++ b/apps/demo-nextjs-app-router/app/queue/page.tsx
@@ -0,0 +1,152 @@
+'use client';
+
+import * as fal from '@fal-ai/serverless-client';
+import { useState } from 'react';
+
+fal.config({
+ proxyUrl: '/api/fal/proxy',
+});
+
+type ErrorProps = {
+ error: any;
+};
+
+function Error(props: ErrorProps) {
+ if (!props.error) {
+ return null;
+ }
+ return (
+
+ Error {props.error.message}
+
+ );
+}
+
+export default function Home() {
+ // Input state
+ const [endpointId, setEndpointId] = useState('');
+ const [input, setInput] = useState('{}');
+ // Result state
+ const [loading, setLoading] = useState(false);
+ const [error, setError] = useState(null);
+ const [result, setResult] = useState(null);
+ const [logs, setLogs] = useState([]);
+ const [elapsedTime, setElapsedTime] = useState(0);
+
+ const reset = () => {
+ setLoading(false);
+ setError(null);
+ setResult(null);
+ setLogs([]);
+ setElapsedTime(0);
+ };
+
+ const run = async () => {
+ reset();
+ setLoading(true);
+ const start = Date.now();
+ try {
+ const result: any = await fal.subscribe(endpointId, {
+ input: JSON.parse(input),
+ logs: true,
+ onQueueUpdate(update) {
+ console.log('queue update');
+ console.log(update);
+ setElapsedTime(Date.now() - start);
+ if (
+ update.status === 'IN_PROGRESS' ||
+ update.status === 'COMPLETED'
+ ) {
+ if (update.logs && update.logs.length > logs.length) {
+ setLogs((update.logs || []).map((log) => log.message));
+ }
+ }
+ },
+ });
+ setResult(result);
+ } catch (error: any) {
+ setError(error);
+ } finally {
+ setLoading(false);
+ setElapsedTime(Date.now() - start);
+ }
+ };
+ return (
+
+
+
+ fal
+ queue
+
+
+
+ setEndpointId(e.target.value)}
+ />
+
+
+
+
+
+
+
+
+
+
+
+
+
JSON Result
+
+ {`Elapsed Time (seconds): ${(elapsedTime / 1000).toFixed(2)}`}
+
+
+ {result
+ ? JSON.stringify(result, null, 2)
+ : '// result pending...'}
+
+
+
+
+
Logs
+
+ {logs.join('\n')}
+
+
+
+
+
+ );
+}
diff --git a/apps/demo-nextjs-app-router/app/whisper/page.tsx b/apps/demo-nextjs-app-router/app/whisper/page.tsx
index db9d386..b1391c4 100644
--- a/apps/demo-nextjs-app-router/app/whisper/page.tsx
+++ b/apps/demo-nextjs-app-router/app/whisper/page.tsx
@@ -113,7 +113,6 @@ export default function WhisperDemo() {
file_name: 'recording.wav',
audio_url: audioFile,
},
- pollInterval: 1000,
logs: true,
onQueueUpdate(update) {
setElapsedTime(Date.now() - start);
diff --git a/apps/demo-nextjs-page-router/pages/index.tsx b/apps/demo-nextjs-page-router/pages/index.tsx
index 2a279d8..7d397d7 100644
--- a/apps/demo-nextjs-page-router/pages/index.tsx
+++ b/apps/demo-nextjs-page-router/pages/index.tsx
@@ -78,7 +78,6 @@ export function Index() {
model_name: 'stabilityai/stable-diffusion-xl-base-1.0',
image_size: 'square_hd',
},
- pollInterval: 3000, // Default is 1000 (every 1s)
logs: true,
onQueueUpdate(update) {
setElapsedTime(Date.now() - start);
diff --git a/libs/client/package.json b/libs/client/package.json
index ed25eb6..01ac312 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.11.0",
+ "version": "0.12.0",
"license": "MIT",
"repository": {
"type": "git",
diff --git a/libs/client/src/function.ts b/libs/client/src/function.ts
index a464a4b..c311307 100644
--- a/libs/client/src/function.ts
+++ b/libs/client/src/function.ts
@@ -1,6 +1,8 @@
+import { getTemporaryAuthToken } from './auth';
import { dispatchRequest } from './request';
import { storageImpl } from './storage';
-import { EnqueueResult, QueueStatus } from './types';
+import { FalStream } from './streaming';
+import { EnqueueResult, QueueStatus, RequestLog } from './types';
import { ensureAppIdFormat, isUUIDv4, isValidUrl, parseAppId } from './utils';
/**
@@ -138,36 +140,22 @@ export async function subscribe(
if (options.onEnqueue) {
options.onEnqueue(requestId);
}
- return new Promise