zoho-workdrive-uploader
v1.0.4
Published
Production-ready Node.js package for secure file uploads to Zoho WorkDrive using OAuth 2.0 refresh token flow. Backend-only, supports file paths, Buffers, and Streams.
Downloads
569
Maintainers
Readme
🚀 Zoho WorkDrive Uploader
The simplest way to upload files to Zoho WorkDrive from Node.js — Secure OAuth 2.0 authentication, automatic token refresh, and zero configuration hassle.
🎯 Perfect for: Express.js APIs, Nest.js backends, serverless functions, and any Node.js application needing Zoho WorkDrive integration.
📋 Table of Contents
- Why Choose This Package?
- Features
- Installation
- Quick Start
- Configuration
- API Reference
- Usage Examples
- Error Handling
- Security Best Practices
- Data Centers
- Testing
- Troubleshooting
- Contributing
- License
💡 Why Choose This Package?
| Feature | Benefit |
|---------|---------|
| ✅ Production-Ready | 98%+ test coverage, battle-tested in production |
| ✅ Zero Token Hassle | Automatic OAuth 2.0 token refresh - set it and forget it |
| ✅ Type-Safe Errors | Custom error classes for precise error handling |
| ✅ Flexible Input | Upload from file path, Buffer, or Stream |
| ✅ Global Support | All 6 Zoho data centers supported (US, IN, EU, AU, JP, CN) |
| ✅ Lightweight | Only 2 dependencies: axios and form-data |
| ✅ Well Documented | Comprehensive docs with real-world examples |
⚠️ Backend Only: This package is designed exclusively for Node.js/Express server environments. Never use it in browser/frontend applications as it would expose your Zoho credentials.
✨ Features
- 🔐 Secure OAuth 2.0 - Automatic token management with refresh token flow
- 📁 Multiple Input Types - Upload from file path, Buffer, or Stream
- 🌍 Multi-Region Support - Works with all Zoho data centers (US, IN, EU, AU, JP, CN)
- ⚡ Token Caching - Efficient token reuse with automatic refresh before expiration
- 🛡️ Comprehensive Error Handling - Custom error classes for different failure scenarios
- 📦 Minimal Dependencies - Only
axiosandform-data - 🧪 Fully Tested - 98%+ code coverage with Jest
- 📝 TypeScript Friendly - Clear JSDoc annotations for IDE support
📦 Installation
# npm
npm install zoho-workdrive-uploader
# yarn
yarn add zoho-workdrive-uploader
# pnpm
pnpm add zoho-workdrive-uploaderRequirements: Node.js 16.0.0 or higher
⚡ Quick Start
Get started in under 5 minutes:
const { ZohoWorkDriveUploader } = require('zoho-workdrive-uploader');
// Initialize the uploader
const uploader = new ZohoWorkDriveUploader({
clientId: 'your_client_id',
clientSecret: 'your_client_secret',
refreshToken: 'your_refresh_token',
parentFolderId: 'your_folder_id',
dataCenter: 'US' // or 'IN', 'EU', 'AU', 'JP', 'CN'
});
// Upload a file - it's that simple!
const result = await uploader.uploadFile('/path/to/document.pdf');
console.log('✅ File uploaded successfully!');
console.log('📎 File ID:', result.fileId);
console.log('🔗 Permalink:', result.permalink);⚙️ Configuration
Constructor Options
| Option | Type | Required | Default | Description |
|--------|------|----------|---------|-------------|
| clientId | string | Yes* | - | Zoho API Client ID |
| clientSecret | string | Yes* | - | Zoho API Client Secret |
| refreshToken | string | Yes* | - | Zoho OAuth Refresh Token |
| parentFolderId | string | Yes* | - | Default Zoho WorkDrive folder ID |
| dataCenter | string | No | 'US' | Zoho data center (US, IN, EU, AU, JP, CN) |
| timeout | number | No | 30000 | Request timeout in milliseconds |
| maxFileSize | number | No | - | Maximum file size in bytes |
*Can also be provided via environment variables
Environment Variables
Create a .env file in your project root:
ZOHO_CLIENT_ID=your_client_id
ZOHO_CLIENT_SECRET=your_client_secret
ZOHO_REFRESH_TOKEN=your_refresh_token
ZOHO_PARENT_FOLDER_ID=your_folder_id
ZOHO_DATA_CENTER=US
ZOHO_TIMEOUT=30000
ZOHO_MAX_FILE_SIZE=104857600Then initialize without constructor options:
require('dotenv').config();
const { ZohoWorkDriveUploader } = require('zoho-workdrive-uploader');
const uploader = new ZohoWorkDriveUploader();📚 API Reference
uploadFile(file, options)
Uploads a file to Zoho WorkDrive.
Parameters:
| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| file | string \| Buffer \| Readable | Yes | File path, Buffer, or Readable stream |
| options.filename | string | Conditional | Required for Buffer/Stream uploads |
| options.parentFolderId | string | No | Override default parent folder |
| options.overrideNameExist | boolean | No | Override existing file with same name |
Returns: Promise<UploadResult>
{
success: true,
fileId: 'abc123',
filename: 'document.pdf',
size: 102400,
parentFolderId: 'folder123',
createdTime: '2024-01-15T10:30:00Z',
modifiedTime: '2024-01-15T10:30:00Z',
type: 'file',
extension: 'pdf',
downloadUrl: 'https://...',
permalink: 'https://...',
rawResponse: { /* full Zoho API response */ }
}getParentFolderId()
Returns the configured default parent folder ID.
getDataCenter()
Returns the configured data center code.
clearTokenCache()
Clears the cached access token, forcing re-authentication on the next request.
💻 Usage Examples
Upload from File Path
const { ZohoWorkDriveUploader } = require('zoho-workdrive-uploader');
const uploader = new ZohoWorkDriveUploader({
clientId: process.env.ZOHO_CLIENT_ID,
clientSecret: process.env.ZOHO_CLIENT_SECRET,
refreshToken: process.env.ZOHO_REFRESH_TOKEN,
parentFolderId: process.env.ZOHO_PARENT_FOLDER_ID
});
async function uploadDocument() {
try {
const result = await uploader.uploadFile('./documents/report.pdf');
console.log('File uploaded successfully!');
console.log('File ID:', result.fileId);
console.log('Download URL:', result.downloadUrl);
} catch (error) {
console.error('Upload failed:', error.message);
}
}Upload from Buffer
const fs = require('fs');
async function uploadFromBuffer() {
const fileBuffer = fs.readFileSync('./image.png');
const result = await uploader.uploadFile(fileBuffer, {
filename: 'uploaded-image.png'
});
console.log('Uploaded:', result.fileId);
}Upload from Stream
const fs = require('fs');
async function uploadFromStream() {
const fileStream = fs.createReadStream('./large-video.mp4');
const result = await uploader.uploadFile(fileStream, {
filename: 'video.mp4'
});
console.log('Uploaded:', result.fileId);
}Express.js + Multer Integration
const express = require('express');
const multer = require('multer');
const { ZohoWorkDriveUploader } = require('zoho-workdrive-uploader');
const app = express();
const upload = multer({ storage: multer.memoryStorage() });
const uploader = new ZohoWorkDriveUploader({
clientId: process.env.ZOHO_CLIENT_ID,
clientSecret: process.env.ZOHO_CLIENT_SECRET,
refreshToken: process.env.ZOHO_REFRESH_TOKEN,
parentFolderId: process.env.ZOHO_PARENT_FOLDER_ID
});
app.post('/upload', upload.single('file'), async (req, res) => {
try {
if (!req.file) {
return res.status(400).json({ error: 'No file uploaded' });
}
const result = await uploader.uploadFile(req.file.buffer, {
filename: req.file.originalname
});
res.json({
success: true,
fileId: result.fileId,
filename: result.filename
});
} catch (error) {
console.error('Upload error:', error);
res.status(500).json({ error: 'Upload failed' });
}
});
app.listen(3000, () => {
console.log('Server running on port 3000');
});🚨 Error Handling
The package provides custom error classes for different failure scenarios:
const {
ZohoWorkDriveUploader,
ConfigurationError,
AuthenticationError,
UploadError,
FileInputError,
ZohoAPIError,
RateLimitError,
NetworkError,
TimeoutError
} = require('zoho-workdrive-uploader');
try {
const result = await uploader.uploadFile('./file.pdf');
} catch (error) {
if (error instanceof ConfigurationError) {
console.error('Configuration issue:', error.message);
} else if (error instanceof AuthenticationError) {
console.error('Authentication failed:', error.message);
} else if (error instanceof FileInputError) {
console.error('Invalid file input:', error.message);
} else if (error instanceof RateLimitError) {
console.error('Rate limited. Retry after:', error.retryAfter, 'seconds');
} else if (error instanceof TimeoutError) {
console.error('Request timed out:', error.message);
} else if (error instanceof NetworkError) {
console.error('Network error:', error.message);
} else if (error instanceof ZohoAPIError) {
console.error('Zoho API error:', error.message);
console.error('Status code:', error.statusCode);
console.error('API error code:', error.apiErrorCode);
} else {
console.error('Unexpected error:', error);
}
}Error Types
| Error Class | Description |
|-------------|-------------|
| ConfigurationError | Missing or invalid configuration parameters |
| AuthenticationError | OAuth token refresh failed |
| FileInputError | Invalid file input (missing file, invalid type) |
| UploadError | General upload failure |
| ZohoAPIError | Zoho API returned an error |
| RateLimitError | API rate limit exceeded (HTTP 429) |
| NetworkError | Network connectivity issues |
| TimeoutError | Request timeout exceeded |
🔒 Security Best Practices
⚠️ Critical Security Guidelines
Never expose credentials in frontend code
- This package is for backend/server use only
- Never bundle with frontend applications (React, Vue, Angular, etc.)
Use environment variables
# Never hardcode credentials in your code export ZOHO_CLIENT_ID=your_client_id export ZOHO_CLIENT_SECRET=your_client_secret export ZOHO_REFRESH_TOKEN=your_refresh_tokenNever commit
.envfiles- Add
.envto your.gitignore - Use
.env.examplefor documentation
- Add
Use HTTPS in production
- Always deploy behind HTTPS
- Never transmit credentials over unencrypted connections
Secure your refresh token
- Store refresh tokens securely
- Rotate tokens periodically
- Revoke tokens if compromised
⚙️ Limitations
- Backend only - Not compatible with browser environments
- No presigned URLs - Direct frontend uploads are not supported
- Single file uploads - Batch uploads require multiple calls
- Rate limits - Subject to Zoho API rate limits
- File size limits - Subject to Zoho WorkDrive storage limits
🔧 Troubleshooting
Common Issues
"Missing required configuration"
- Ensure all required options are provided via constructor or environment variables
"Token refresh failed"
- Verify your client ID, client secret, and refresh token are correct
- Check that your Zoho API credentials have WorkDrive scope
- Ensure your refresh token hasn't expired
"Invalid data center"
- Use one of:
US,IN,EU,AU,JP,CN - Match your Zoho account's region
"Rate limit exceeded"
- Implement exponential backoff
- Check
error.retryAfterfor wait time
"Upload timed out"
- Increase
timeoutoption for large files - Check network connectivity
🌍 Data Centers
Zoho WorkDrive Uploader supports all Zoho data centers worldwide:
| Region | Code | Accounts URL | API Base URL |
|--------|------|--------------|--------------|
| 🇺🇸 United States | US | accounts.zoho.com | www.zohoapis.com |
| 🇮🇳 India | IN | accounts.zoho.in | www.zohoapis.in |
| 🇪🇺 Europe | EU | accounts.zoho.eu | www.zohoapis.eu |
| 🇦🇺 Australia | AU | accounts.zoho.com.au | www.zohoapis.com.au |
| 🇯🇵 Japan | JP | accounts.zoho.jp | www.zohoapis.jp |
| 🇨🇳 China | CN | accounts.zoho.com.cn | www.zohoapis.com.cn |
🧪 Testing
This package includes a comprehensive test suite using Jest with 98%+ code coverage.
# Run all tests
npm test
# Run tests with coverage report
npm run test:coverage
# Run tests in watch mode
npm run test:watchTest Coverage
| Metric | Coverage | |--------|----------| | Statements | 98%+ | | Branches | 96%+ | | Functions | 100% | | Lines | 98%+ |
🤝 Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
📄 License
MIT © 2026 appletosolutions
🔗 Related Links
🏷️ Keywords
zoho workdrive file-upload oauth2 node.js express cloud-storage zoho-api zoho-workdrive file-uploader backend server-side refresh-token automatic-token-refresh
