npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

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

Readme

🚀 Zoho WorkDrive Uploader

npm version npm downloads npm downloads license node version coverage GitHub stars

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?

| 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 axios and form-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-uploader

Requirements: 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=104857600

Then 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

  1. Never expose credentials in frontend code

    • This package is for backend/server use only
    • Never bundle with frontend applications (React, Vue, Angular, etc.)
  2. 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_token
  3. Never commit .env files

    • Add .env to your .gitignore
    • Use .env.example for documentation
  4. Use HTTPS in production

    • Always deploy behind HTTPS
    • Never transmit credentials over unencrypted connections
  5. 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.retryAfter for wait time

"Upload timed out"

  • Increase timeout option 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:watch

Test Coverage

| Metric | Coverage | |--------|----------| | Statements | 98%+ | | Branches | 96%+ | | Functions | 100% | | Lines | 98%+ |


🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. 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