
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
A comprehensive SDK designed to simplify interaction with the FlowScale ComfyUI API. This library works in both Node.js and browser environments with full TypeScript support.
For secure frontend usage, use Proxy Mode to keep your API key safe on the backend:
// ✅ SECURE: No API key exposed to frontend users
const flowscale = new FlowscaleAPI({
baseUrl: 'https://your-backend-proxy.com', // Your secure backend proxy
proxyMode: true, // Enable proxy mode
customHeaders: {
'Authorization': 'Bearer jwt-token-here' // Use JWT tokens instead
}
});
Recommendation: For production apps, use Backend-Only approach for maximum security and simplicity.
If you use the SDK directly in the browser with an API key, it will be exposed to end users. Only do this for development:
// ⚠️ WARNING: API key will be visible to users
const flowscale = new FlowscaleAPI({
apiKey: 'your-api-key',
baseUrl: 'your-api-url',
allowDangerouslyExposeApiKey: true // Required acknowledgment
});
Install the Flowscale SDK by npm, yarn, pnpm or bun:
npm install flowscale
yarn add flowscale
pnpm install flowscale
bun install flowscale
To get started, import the Flowscale SDK into your project:
import { FlowscaleAPI } from 'flowscale';
// Node.js Environment (Recommended)
const apiKey = process.env.FLOWSCALE_API_KEY;
const apiUrl = process.env.FLOWSCALE_API_URL;
const flowscale = new FlowscaleAPI({
apiKey,
baseUrl: apiUrl
});
// Browser Environment (Not Recommended)
const flowscale = new FlowscaleAPI({
apiKey: 'your-api-key', // ⚠️ WARNING: This will be exposed to users
baseUrl: 'https://your-api-url.pod.flowscale.ai',
allowDangerouslyExposeApiKey: true // Explicitly acknowledge the security risk
});
.env files for configurationEnvironment Variables: Add the following to your .env file:
FLOWSCALE_API_KEY=your-api-key
FLOWSCALE_API_URL=https://your-api-url.pod.flowscale.ai
Below is a detailed guide to the SDK methods, including descriptions, usage, and response formats.
checkHealth()Description: Check the health status of the Flowscale platform, including the status of containers and services.
Usage:
const health = await flowscale.checkHealth();
console.log('API Health:', health);
Response Example:
{
"status": "success",
"data": [
{
"container": "container #1",
"status": "idle"
},
{
"container": "container #2",
"status": "running"
}
]
}
getQueue()Description: Retrieve the current status of the workflow queue, including running and pending jobs.
Usage:
const queue = await flowscale.getQueue();
console.log('Queue Details:', queue);
Response Example:
{
"status": "success",
"data": [
{
"container": "container #1",
"queue": {
"queue_running": [
[
0,
"2a0babc4-acce-4521-9576-00fa0e6ecc91"
]
],
"queue_pending": [
[
1,
"5d60718a-7e89-4c64-b32d-0d1366b44e2a"
]
]
}
}
]
}
getWorkflows()Description: Retrieves the list of all deployed workflows available in the cluster.
Usage:
const workflows = await flowscale.getWorkflows();
console.log('Available Workflows:', workflows);
Response Example:
{
"status": "success",
"data": [
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Text to Image",
"description": "Generate an image from text input",
"inputs": "{ \"text_51536\": \"string\" }",
"outputs": "{ \"image_output\": \"image\" }"
},
{
"id": "660f9411-f30c-52e5-b827-557766551111",
"name": "Image to Image",
"description": "Transform an existing image",
"inputs": "{ \"image_input\": \"image\", \"prompt\": \"string\" }",
"outputs": "{ \"transformed_image\": \"image\" }"
}
]
}
executeWorkflow(workflowId, data, groupId?)Description:
Trigger a workflow execution using its unique workflowId. This method starts the workflow but does not wait for completion - it returns immediately with the run_id and workflow_id. To wait for results, use executeWorkflowAsync or manually poll with getOutput.
Parameters:
workflowId (string): The unique ID of the workflow.data (object): Input parameters for the workflow.groupId (string, optional): A custom identifier for grouping runs.Usage:
const workflowId = "550e8400-e29b-41d4-a716-446655440000"; // UUID format
const groupId = "test_group";
const inputs = {
"text_51536": "Prompt test",
"image_1234": { /* File or Blob of image */ },
"video_1239": { /* File or Blob of video */ }
};
const result = await flowscale.executeWorkflow(workflowId, inputs, groupId);
console.log('Workflow Result:', result);
Response Example:
{
"status": "success",
"data": {
"run_id": "808f34d0-ef97-4b78-a00f-1268077ea6db",
"workflow_id": "550e8400-e29b-41d4-a716-446655440000"
}
}
executeWorkflowAsync(workflowId, data, groupId?, pollIntervalMs?, timeoutMs?, options?)Description:
Execute a workflow and automatically wait for all outputs by polling. This is a convenience method that combines executeWorkflow and getOutput with automatic polling. Unlike executeWorkflow, this method waits for completion and returns the actual workflow outputs.
Parameters:
workflowId (string): The unique ID of the workflow.data (object): Input parameters for the workflow.groupId (string, optional): A custom identifier for grouping runs.pollIntervalMs (number, optional): Polling interval in milliseconds (default: 2000).timeoutMs (number, optional): Maximum time to wait for results in milliseconds (default: 600000 - 10 minutes).options (object, optional): Additional async execution options.onIntermediateResponse (function, options only): Callback fired for intermediate API responses while polling. Useful for queue/progress UI updates.Usage:
const workflowId = "550e8400-e29b-41d4-a716-446655440000"; // UUID format
const inputs = {
"text_51536": "Prompt test",
"image_1234": { /* File or Blob of image */ }
};
try {
const result = await flowscale.executeWorkflowAsync(workflowId, inputs);
console.log('Workflow Result:', result);
} catch (error) {
if (error.message.includes('timed out')) {
console.error('Workflow took too long to complete');
} else {
console.error('Workflow error:', error);
}
}
Usage (with intermediate updates):
const result = await flowscale.executeWorkflowAsync(
workflowId,
inputs,
groupId,
2000,
600000,
{
onIntermediateResponse: (update) => {
// update.type: workflow_submitted | run_status | output_status | poll_retry | completed
console.log('Async update:', update);
}
}
);
Response Example:
{
"status": "success",
"data": [
{
"filename": "output_image_1.png",
"download_url": "https://runs.s3.amazonaws.com/generations/...",
"generation_status": "success"
},
{
"filename": "output_text_1",
"file_content": "hello world",
"generation_status": "success"
}
]
}
Each output entry contains either:
download_url for binary/media outputsfile_content for text/non-binary outputsexecuteWorkflowAsync now always returns array output format (GetAllOutputsResponse).
If you migrated from v1.x and previously accessed result.data.download_url directly, update to iterate outputs:
const result = await flowscale.executeWorkflowAsync(workflowId, data);
result.data.forEach((output) => {
console.log(output.download_url || output.file_content);
});
getOutput(filename)Description:
Fetch the output of a completed workflow using its filename. Outputs typically include downloadable files or results.
Parameters:
filename (string): The name of the output file.Usage:
const output = await flowscale.getOutput('filename_prefix_58358_5WWF7GQUYF.png');
console.log('Workflow Output:', output);
Response Example:
{
"status": "success",
"data": {
"download_url": "https://runs.s3.amazonaws.com/generations/...",
"generation_status": "success"
}
}
For text outputs, data may contain file_content instead of download_url.
cancelRun(runId)Description:
Cancel a running workflow execution using its unique runId.
Parameters:
runId (string): The unique identifier of the running workflow.Usage:
const result = await flowscale.cancelRun('808f34d0-ef97-4b78-a00f-1268077ea6db');
console.log('Cancellation Result:', result);
Response Example:
{
"status": "success",
"data": "Run cancelled successfully"
}
getRun(runId)Description: Retrieve detailed information about a specific workflow run.
Parameters:
runId (string): The unique identifier of the run.Usage:
const runDetails = await flowscale.getRun('808f34d0-ef97-4b78-a00f-1268077ea6db');
console.log('Run Details:', runDetails);
Response Example:
{
"status": "success",
"data": {
"_id": "808f34d0-ef97-4b78-a00f-1268077ea6db",
"status": "completed",
"inputs": [
{
"path": "text_51536",
"value": "a man riding a bike"
}
],
"outputs": [
{
"filename": "filename_prefix_58358_5WWF7GQUYF.png",
"url": "https://runs.s3.amazonaws.com/generations/..."
}
]
}
}
getRuns(groupId)Description:
Retrieve all workflow runs associated with a specific groupId. If no groupId is provided, all runs for the team are returned.
Parameters:
groupId (string, optional): The identifier for grouping runs.Usage:
const runs = await flowscale.getRuns('test_group');
console.log('Runs for Group:', runs);
// Get all runs for the team
const allRuns = await flowscale.getRuns();
console.log('All Runs:', allRuns);
Response Example:
{
"status": "success",
"data": {
"group_id": "test_group",
"count": 2,
"runs": [
{
"_id": "cc29a72d-75b9-4c7b-b991-ccaf2a04d6ea",
"status": "completed",
"outputs": [
{
"filename": "filename_prefix_58358_G3DRLIVVYP.png",
"url": "https://runs.s3.amazonaws.com/generations/..."
}
]
}
]
}
}
subscribeRunEvents(runId, options?)Description:
Subscribe to run-level events over SSE using the new /api/v1/runs/{run_id}/events endpoint.
Parameters:
runId (string): The run ID to stream events for.options (object, optional):
fromSeq (number, optional): Replay from this sequence number.signal (AbortSignal, optional): External abort signal.onOpen (function, optional): Called when stream response opens.onEvent (function, optional): Called for each parsed SSE event payload.onError (function, optional): Called on stream errors.onClose (function, optional): Called when stream closes.Returns:
{ close, done }
close() aborts the SSE stream.done is a promise that resolves when stream ends.Usage:
const stream = flowscale.subscribeRunEvents(runId, {
fromSeq: 0,
onEvent: (event) => {
console.log('Run event:', event.id, event.data);
},
onError: (error) => {
console.error('Run event stream error:', error);
},
onClose: () => {
console.log('Run event stream closed');
},
});
// Optional: stop manually
// stream.close();
await stream.done;
Node.js < 18 note: pass a custom fetchImpl in SDK config for SSE support.
const flowscale = new FlowscaleAPI({
apiKey,
baseUrl,
fetchImpl: fetch // e.g. from undici/node-fetch polyfill
});
.env files and libraries like dotenv for easy environment management.const flowscale = new FlowscaleAPI({
baseUrl: 'https://your-backend-proxy.com',
proxyMode: true,
customHeaders: {
'Authorization': 'Bearer your-jwt-token',
'X-User-ID': 'user123' // Additional custom headers
}
});
// Update JWT token without recreating SDK instance
flowscale.updateCustomHeaders({
'Authorization': 'Bearer new-jwt-token'
});
// Get current headers
const headers = flowscale.getCustomHeaders();
// Clear all custom headers
flowscale.clearCustomHeaders();
// Backend - Use Flowscale SDK
const flowscale = new FlowscaleAPI({
apiKey: process.env.FLOWSCALE_API_KEY,
baseUrl: process.env.FLOWSCALE_API_URL
});
app.post('/api/workflows/execute', async (req, res) => {
const result = await flowscale.executeWorkflowAsync(req.body.workflowId, req.body.data);
res.json(result);
});
// Frontend - Simple API calls
const result = await fetch('/api/workflows/execute', {
method: 'POST',
headers: { 'Authorization': 'Bearer ' + token },
body: JSON.stringify({ workflowId, data })
});
// Backend - SDK + Proxy endpoints
const flowscale = new FlowscaleAPI({
apiKey: process.env.FLOWSCALE_API_KEY,
baseUrl: process.env.FLOWSCALE_API_URL
});
// Frontend - SDK through proxy
const flowscale = new FlowscaleAPI({
baseUrl: 'https://your-backend.com',
proxyMode: true,
customHeaders: { 'Authorization': 'Bearer jwt-token' }
});
See examples/secure-frontend-example.html and examples/backend-proxy-example.js for complete implementation examples.
We welcome contributions! Please see our Contributing Guide for details on how to:
This project is licensed under the BSD 3-Clause License - see the LICENSE file for details.
For security concerns, please review our Security Policy and report vulnerabilities to security@flowscale.ai.
For any questions or assistance:
Made with ❤️ by the Flowscale team
Simplify your workflow management with the Flowscale JavaScript SDK. Happy coding! 🚀
FAQs
An NPM library for communicating with the Flowscale APIs
We found that flowscale demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.