@ifzai/connect2dify
v1.0.8
Published
A comprehensive TypeScript client for the Dify API, providing a clean and modular interface for chat, workflow, file management, and application interactions.
Maintainers
Readme
@ifzai/connect2dify
A comprehensive TypeScript client for the Dify API, providing a clean and modular interface for chat, workflow, file management, and application interactions.
Features
- 🚀 Modular Architecture: Organized into focused API modules (Chat, Conversation, Workflow, File, App)
- 🔄 Streaming Support: Built-in support for real-time streaming responses
- 💪 TypeScript: Full type safety with comprehensive type definitions
- 🌐 Universal: Works in both browser and Node.js environments
- 📦 Tree Shakable: Import only the modules you need
- 🔧 Configurable: Flexible configuration options
- 🔄 Backward Compatible: Deprecated methods maintain compatibility
Installation
npm install @ifzai/connect2dify
# or
pnpm add @ifzai/connect2dify
# or
yarn add @ifzai/connect2difyQuick Start
Basic Usage
import { DifyClient } from '@ifzai/connect2dify';
const client = new DifyClient({
baseUrl: 'https://api.dify.ai',
apiKey: 'your-api-key',
});
// Send a chat message (agent-chat apps only support streaming)
const response = await client.chat.sendMessage({
user: 'user-123',
query: 'Hello, how can you help me?',
response_mode: 'streaming',
inputs: {}, // Required for agent-chat applications
});
console.log(response.answer);Streaming Responses
// Chat streaming example
const streamParams = {
user: 'user-123',
query: 'Tell me a story',
response_mode: 'streaming' as const,
};
const result = await client.chat.sendMessage(streamParams);
if (Array.isArray(result)) {
// Handle streaming chunks
for (const chunk of result) {
console.log(chunk.answer);
}
}Workflow Execution
// Execute a workflow in blocking mode
const workflowResponse = await client.workflow.runWorkflow({
inputs: {
query: 'What is artificial intelligence?',
},
user: 'user-123',
response_mode: 'blocking',
});
console.log('Workflow result:', workflowResponse.data.outputs);
// Execute a workflow with streaming for real-time output
const streamingWorkflow = await client.workflow.runWorkflow({
inputs: {
query: 'Tell me a short story',
},
user: 'user-123',
response_mode: 'streaming',
chunkCompletionCallback: (chunk) => {
if (chunk.event === 'text_chunk' && chunk.data?.text) {
process.stdout.write(chunk.data.text); // Real-time text streaming
}
},
});Using Individual API Modules
import { ChatAPI, WorkflowAPI } from '@ifzai/connect2dify';
const config = {
baseUrl: 'https://api.dify.ai',
apiKey: 'your-api-key',
};
const chatAPI = new ChatAPI(config);
const workflowAPI = new WorkflowAPI(config);
// Use APIs independently
const chatResponse = await chatAPI.sendMessage({
user: 'user-123',
query: 'Hello!',
});
const workflowResponse = await workflowAPI.runWorkflow({
user: 'user-123',
inputs: { text: 'Process this' },
});Workflow Examples
Basic Workflow Execution
import { DifyClient } from '@ifzai/connect2dify';
const client = new DifyClient({
baseUrl: 'https://api.dify.ai/v1',
apiKey: 'your-workflow-api-key',
});
// Execute workflow in blocking mode
const response = await client.workflow.runWorkflow({
inputs: {
query: 'What is the weather like today?',
},
user: 'user-123',
response_mode: 'blocking',
});
console.log('Workflow result:', response.data.outputs);Streaming Workflow with Real-time Output
// Execute workflow with real-time streaming
const streamingResponse = await client.workflow.runWorkflow({
inputs: {
query: 'Tell me a short story about a robot.',
},
user: 'user-123',
response_mode: 'streaming',
chunkCompletionCallback: (chunk) => {
// Handle different event types
if (chunk.event === 'workflow_started') {
console.log('🎬 Workflow started...');
} else if (chunk.event === 'node_started') {
console.log(`🔧 Node started: ${chunk.data?.title || 'Unknown'}`);
} else if (chunk.event === 'text_chunk' && chunk.data?.text) {
// This is the actual streaming text - display it word by word
process.stdout.write(chunk.data.text);
} else if (chunk.event === 'node_finished') {
console.log(`✅ Node finished: ${chunk.data?.title || 'Unknown'}`);
} else if (chunk.event === 'workflow_finished') {
console.log('\n🏁 Workflow finished!');
}
},
});
console.log('Streaming completed!');Workflow with Custom Inputs
// Execute workflow with custom parameters
const customResponse = await client.workflow.runWorkflow({
inputs: {
query: 'How do I cook pasta step by step?',
language: 'en',
detail_level: 'comprehensive',
// Add any custom inputs your workflow expects
},
user: 'user-123',
response_mode: 'blocking',
});
console.log('Custom workflow result:', customResponse.data.outputs);Retrieving Workflow Information
// First execute a workflow to get a workflow_run_id
const runResponse = await client.workflow.runWorkflow({
inputs: { query: 'Hello, this is a test.' },
user: 'user-123',
response_mode: 'blocking',
});
// Then get detailed information about the workflow run
if (runResponse.workflow_run_id) {
const workflowInfo = await client.workflow.getWorkflow({
workflow_run_id: runResponse.workflow_run_id,
});
console.log('Workflow Details:');
console.log(`- Status: ${workflowInfo.status}`);
console.log(`- Total Steps: ${workflowInfo.total_steps}`);
console.log(`- Total Tokens: ${workflowInfo.total_tokens}`);
console.log(`- Execution Time: ${workflowInfo.elapsed_time}s`);
}File Upload with Workflow
// Upload a file first
const fileResponse = await client.file.uploadFile({
file: fileBuffer, // or File object in browser
user: 'user-123',
});
// Use the uploaded file in a workflow
const workflowResponse = await client.workflow.runWorkflow({
inputs: {
query: 'Analyze this document',
},
user: 'user-123',
response_mode: 'blocking',
files: [
{
type: 'document',
transfer_method: 'local_file',
upload_file_id: fileResponse.id,
},
],
});API Reference
DifyClient
The main client class that provides access to all API modules:
const client = new DifyClient({
baseUrl: 'https://api.dify.ai/v1', // Required: Your Dify API base URL
apiKey: 'your-api-key', // Required: Your API key
defaultResponseMode: 'blocking', // Optional: 'blocking' | 'streaming'
defaultUser: 'default-user', // Optional: Default user ID for requests
requestOptions: {
// Optional: Additional request configuration
extraHeaders: {
'Custom-Header': 'value',
'X-Source': 'my-app',
},
timeout: 30000, // Request timeout in milliseconds
},
});Configuration Options
| Option | Type | Required | Default | Description |
| ----------------------------- | --------------------------- | -------- | ------------ | ------------------------------------------------------- |
| baseUrl | string | ✅ | - | Your Dify API base URL (e.g., https://api.dify.ai/v1) |
| apiKey | string | ✅ | - | Your application API key from Dify dashboard |
| defaultResponseMode | 'blocking' \| 'streaming' | ❌ | 'blocking' | Default response mode for API calls |
| defaultUser | string | ❌ | - | Default user ID to use when not specified in requests |
| requestOptions.extraHeaders | Record<string, string> | ❌ | {} | Additional HTTP headers to include in requests |
| requestOptions.timeout | number | ❌ | 60000 | Request timeout in milliseconds |
Environment Variables
You can also configure the client using environment variables:
# .env file
DIFY_API_BASE_URL=https://api.dify.ai/v1
DIFY_API_KEY=your-api-key-here
DIFY_DEFAULT_USER=default-user-id// Use environment variables
const client = new DifyClient({
baseUrl: process.env.DIFY_API_BASE_URL || 'https://api.dify.ai/v1',
apiKey: process.env.DIFY_API_KEY,
defaultUser: process.env.DIFY_DEFAULT_USER,
});Chat API (client.chat)
sendMessage(params)- Send a chat message (agent-chat apps only support streaming mode)getMessages(params)- Get conversation messagescreateMessageFeedback(params)- Provide feedback on a messagegetMessageSuggests(params)- Get suggested questionsstopMessageResponse(params)- Stop a message response
Conversation API (client.conversation)
getConversations(params)- List conversationsdeleteConversation(params)- Delete a conversationrenameConversation(params)- Rename a conversation
Workflow API (client.workflow)
runWorkflow(params)- Execute a workflow (supports both blocking and streaming)getWorkflow(params)- Get workflow detailsstopWorkflowTask(params)- Stop a workflow taskgetWorkflowLogs(params)- Get workflow execution logs
File API (client.file)
uploadFile(params)- Upload a fileaudioToText(params)- Convert audio to text
App API (client.app)
getParameters()- Get application parametersgetInfo()- Get application informationgetMeta()- Get application metadatasendCompletionMessage(params)- Send completion message (supports both blocking and streaming)stopCompletionMessage(params)- Stop completion message
Environment Support
This package works in both browser and Node.js environments using modern web APIs:
- ✅ Node.js 18+ (native fetch and ReadableStream support)
- ✅ Modern browsers (Chrome 66+, Firefox 65+, Safari 12+)
- ✅ Edge runtime environments (Vercel Edge, Cloudflare Workers)
- ❌ Node.js < 18 (requires fetch polyfill)
Error Handling
Basic Error Handling
try {
const response = await client.chat.sendMessage({
user: 'user-123',
query: 'Hello!',
});
console.log('Success:', response.answer);
} catch (error) {
console.error('API Error:', error.message);
// Handle specific error types
if (error.message.includes('unauthorized')) {
console.error('Check your API key');
} else if (error.message.includes('quota')) {
console.error('API quota exceeded');
}
}Workflow Error Handling
try {
const response = await client.workflow.runWorkflow({
inputs: { query: 'Process this data' },
user: 'user-123',
response_mode: 'blocking',
});
// Check workflow execution status
if (response.data.status === 'failed') {
console.error('Workflow failed:', response.data.error);
return;
}
console.log('Workflow succeeded:', response.data.outputs);
} catch (error) {
console.error('Workflow execution error:', error.message);
// Handle specific workflow errors
if (error.message.includes('workflow not found')) {
console.error('Check your workflow ID and permissions');
} else if (error.message.includes('invalid inputs')) {
console.error('Check your input parameters match workflow requirements');
}
}Streaming Error Handling
try {
const result = await client.workflow.runWorkflow({
inputs: { query: 'Tell me a story' },
user: 'user-123',
response_mode: 'streaming',
chunkCompletionCallback: (chunk) => {
// Handle streaming errors
if (chunk.event === 'error') {
console.error('Streaming error:', chunk.data?.error);
return;
}
// Process successful chunks
if (chunk.event === 'text_chunk' && chunk.data?.text) {
process.stdout.write(chunk.data.text);
}
},
});
} catch (error) {
if (error.message.includes('Streaming is not supported')) {
// Fallback to blocking mode
console.log('Falling back to blocking mode...');
const response = await client.workflow.runWorkflow({
inputs: { query: 'Tell me a story' },
user: 'user-123',
response_mode: 'blocking',
});
console.log(response.data.outputs);
} else {
console.error('Streaming workflow failed:', error.message);
}
}Migration from Previous Versions
The new modular structure provides a cleaner API while maintaining backward compatibility:
// Old way (still works, but deprecated)
const response = await client.sendMessage(params);
const workflowResult = await client.runWorkflow(params);
// New way (recommended)
const response = await client.chat.sendMessage(params);
const workflowResult = await client.workflow.runWorkflow(params);Running Examples
This package includes comprehensive examples demonstrating real-world usage patterns. All examples use actual Dify API endpoints and showcase different functionality.
Prerequisites
Before running examples, ensure you have:
- Node.js 18+ installed
- Valid Dify API credentials (API key and base URL)
- Dependencies installed:
pnpm install
Available Examples
1. Comprehensive Workflow Demo
Location: examples/comprehensive-workflow-demo.ts
Run Command:
npm run example:workflowWhat it demonstrates:
- ✅ Blocking workflow execution with timing
- 🔄 Streaming workflow execution with real-time text output
- ⚙️ Custom input parameters
- 📊 Workflow run information retrieval
- ✅ Parameter validation
- 🎬 Event handling for different workflow stages
Sample Output:
🎯 Comprehensive Dify Workflow Demo
===================================
📋 Test 1: Blocking Workflow Execution
--------------------------------------
✅ Blocking execution completed in 6.852s
Response structure:
- Task ID: 95cc6b94-22ea-468d-94f8-8ecd46601fc1
- Status: succeeded
- Total Tokens: 268
🔄 Test 2: Streaming Workflow Execution
---------------------------------------
🚀 Starting streaming workflow...
📝 Streaming output (word by word):
---
Here's a short story about a curious robot... [streaming text appears here]
✅ Streaming execution completed in 13.708s
- Total chunks received: 428
- Event type distribution: { text_chunk: 420, workflow_started: 1, ... }2. API Debugging Tool
Location: examples/debug-api.ts
Run Command:
npm run debug:apiWhat it demonstrates:
- 🔍 App info and parameters retrieval
- 💬 Chat completion API usage
- 🔧 Workflow API with detailed logging
- 🐛 Error analysis and troubleshooting
3. Raw API Testing
Location: examples/raw-api-test.js
Run Command:
npm run test:rawWhat it demonstrates:
- 🧪 Low-level API testing with raw fetch calls
- 📡 Direct HTTP request/response analysis
- 🔧 API connectivity troubleshooting
- ⚡ Bypasses client library for pure API testing
Configuring Examples
Most examples include API credentials that you'll need to update:
// Update these values in the example files
const client = new DifyClient({
baseUrl: 'https://api.dify.ai/v1', // Your Dify instance URL
apiKey: 'your-api-key-here', // Your workflow/app API key
});
const userId = 'your-user-id'; // Your user identifierExample Output Features
The examples showcase:
- Real-time Streaming: Watch AI responses generate word-by-word
- Performance Metrics: Execution time, token usage, chunk counts
- Event Tracking: Workflow progression through different stages
- Error Handling: Robust error catching and user-friendly messages
- Type Safety: Full TypeScript integration with proper typing
Creating Custom Examples
You can create your own examples by following this pattern:
import { DifyClient } from '../src/index.js';
async function myCustomExample() {
const client = new DifyClient({
baseUrl: 'https://api.dify.ai/v1',
apiKey: 'your-api-key',
});
try {
const response = await client.workflow.runWorkflow({
inputs: { query: 'Your custom input' },
user: 'your-user-id',
response_mode: 'streaming',
chunkCompletionCallback: (chunk) => {
// Handle streaming chunks
console.log('Received chunk:', chunk.event);
},
});
console.log('Success:', response);
} catch (error) {
console.error('Error:', error.message);
}
}
myCustomExample().catch(console.error);Troubleshooting Examples
If examples fail to run:
- Check API credentials - Ensure your API key and base URL are correct
- Verify network connectivity - Test if you can reach the Dify API
- Review console output - Examples provide detailed error messages
- Check API quotas - Ensure you have sufficient API credits
- Validate workflow configuration - Make sure your workflow accepts the input parameters
Setup
Install the dependencies:
pnpm installGet started
Build the library:
pnpm buildBuild the library in watch mode:
pnpm devCommit Convention
This project follows Conventional Commits specification. All commit messages must be formatted as:
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]Types
- feat: A new feature
- fix: A bug fix
- docs: Documentation only changes
- style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
- refactor: A code change that neither fixes a bug nor adds a feature
- perf: A code change that improves performance
- test: Adding missing tests or correcting existing tests
- build: Changes that affect the build system or external dependencies
- ci: Changes to our CI configuration files and scripts
- chore: Other changes that don't modify src or test files
- revert: Reverts a previous commit
Examples
feat: add user authentication
fix: resolve memory leak in data processing
docs: update API documentation
style: format code with prettier
refactor: extract utility functions
perf: optimize database queries
test: add unit tests for user service
build: update dependencies
ci: add automated testing workflow
chore: update .gitignoreGit Hooks
This project uses Husky to run git hooks:
- pre-commit: Runs code formatting and tests
- commit-msg: Validates commit message format
The hooks will automatically run when you commit. If they fail, the commit will be rejected.
