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

frappe-js-client

v2.3.7

Published

Next-generation TS/JS client for Frappe REST APIs, built on axios for robust, type-safe integration.

Readme

Frappe JS Client

npm version License: MIT TypeScript

A modern, type-safe TypeScript/JavaScript client for Frappe Framework applications. Built with Axios for robust HTTP communication and comprehensive error handling.

📋 Table of Contents

✨ Features

  • 🔐 Authentication: Multiple auth methods (username/password, OTP, token-based)
  • 🗄️ Database Operations: Full CRUD operations with filtering, sorting, and pagination
  • 📁 File Management: Upload, download, and manage files with progress tracking
  • 🌐 API Integration: Direct access to Frappe API endpoints
  • 🛡️ Type Safety: Full TypeScript support with comprehensive type definitions
  • Performance: Built on Axios with optimized request handling
  • 🔄 Error Handling: Standardized error responses and handling
  • 🎯 Permission System: Built-in permission checking and management

📦 Installation

npm install frappe-js-client
# or
yarn add frappe-js-client
# or
pnpm add frappe-js-client

🚀 Quick Start

import { FrappeApp } from 'frappe-js-client'

// Initialize the client
const app = new FrappeApp('https://your-frappe-site.com')

// Authenticate
const auth = app.auth()
await auth.loginWithUsernamePassword({
    username: 'admin',
    password: 'password',
    device: 'desktop',
})

// Database operations
const db = app.db()
const users = await db.getDocList('User', {
    fields: ['name', 'email', 'first_name'],
    filters: [['user_type', '=', 'System User']],
    limit: 10,
})

// File operations
const file = app.file()
const uploadResult = await file.uploadFile(fileBlob, {
    isPrivate: true,
    folder: 'Home/Documents',
})

// API calls
const call = app.call()
const response = await call.get('frappe.ping')

📚 API Reference

FrappeApp

The main class for interacting with a Frappe instance.

class FrappeApp {
    constructor(url: string, tokenParams?: TokenParams, name?: string, customHeaders?: object)
}

Parameters

  • url (string): The base URL of your Frappe instance
  • tokenParams (optional): Configuration for token-based authentication
  • name (optional): Name for the app instance (defaults to 'FrappeApp')
  • customHeaders (optional): Custom headers to include in all requests

Methods

  • auth(): Returns authentication handler
  • db(): Returns database operations handler
  • file(): Returns file operations handler
  • call(): Returns API call handler
  • client(): Returns client operations handler
  • perms(): Returns permission handler

🔐 Authentication

Basic Authentication

const auth = app.auth()

// Login with username and password
const response = await auth.loginWithUsernamePassword({
    username: 'admin',
    password: 'password',
    device: 'desktop',
})

// Login with OTP
const otpResponse = await auth.loginWithUsernamePassword({
    otp: '123456',
    tmp_id: 'temp123',
    device: 'mobile',
})

// Get current user
const currentUser = await auth.getLoggedInUser()

// Logout
await auth.logout()

// Password reset
await auth.forgetPassword('[email protected]')

Token-Based Authentication

// Initialize with token authentication
const app = new FrappeApp('https://your-site.com', {
    useToken: true,
    token: () => localStorage.getItem('token'),
    type: 'Bearer',
})

🗄️ Database Operations

Document Operations

const db = app.db()

// Get a single document
const user = await db.getDoc('User', 'administrator')

// Get document list with filters
const tasks = await db.getDocList('Task', {
    fields: ['name', 'subject', 'status', 'assigned_to'],
    filters: [['status', '=', 'Open']],
    orderBy: { field: 'creation', order: 'desc' },
    limit: 20,
})

// Create a new document
const newTask = await db.createDoc('Task', {
    subject: 'New Task',
    status: 'Open',
    description: 'Task description',
})

// Update a document
await db.updateDoc('Task', newTask.name, {
    status: 'Completed',
    completed_on: new Date().toISOString(),
})

// Delete a document
await db.deleteDoc('Task', newTask.name)

// Get the last document
const lastTask = await db.getLastDoc('Task', {
    filters: [['status', '=', 'Open']],
})

Advanced Filtering

// Complex filters
const filteredDocs = await db.getDocList('Task', {
    filters: [
        ['status', '=', 'Open'],
        ['priority', 'in', ['High', 'Medium']],
        ['creation', '>=', '2024-01-01'],
    ],
    orFilters: [
        ['assigned_to', '=', 'admin'],
        ['owner', '=', 'admin'],
    ],
    groupBy: 'status',
    limit: 50,
})

📁 File Operations

File Upload

const file = app.file()

// Basic file upload
const uploadResult = await file.uploadFile(fileBlob, {
    isPrivate: true,
    folder: 'Home/Documents',
})

// Upload with progress tracking
const result = await file.uploadFile(fileBlob, { isPrivate: false }, (uploaded, total) => {
    const progress = (uploaded / total) * 100
    console.log(`Upload progress: ${progress.toFixed(2)}%`)
})

// Upload with custom metadata
const response = await file.uploadFile(fileBlob, {
    doctype: 'Task',
    docname: 'TASK-001',
    fieldname: 'attachment',
    otherData: {
        category: 'Important',
        tags: 'urgent,review',
    },
})

File Download

const downloader = new FrappeFileDownload(axiosInstance)
const fileBlob = await downloader.downloadFile('https://your-site.com/files/document.pdf')

🌐 API Calls

HTTP Methods

const call = app.call()

// GET request
const response = await call.get('frappe.ping')

// GET with parameters
const users = await call.get('frappe.user.get_users', {
    filters: { user_type: 'System User' },
    limit: 10,
})

// POST request
const result = await call.post('frappe.handler', {
    data: { key: 'value' },
})

// PUT request
await call.put('frappe.user.update_prefs', {
    user: 'admin',
    preferences: { theme: 'dark' },
})

// DELETE request
await call.delete('frappe.user.delete_user', {
    user: 'test_user',
})

🛡️ Error Handling

The SDK provides standardized error handling with detailed error information:

try {
    await db.createDoc('Task', { subject: 'New Task' })
} catch (error) {
    const frappeError = error as Error

    console.error(`HTTP Status: ${frappeError.httpStatus}`)
    console.error(`Message: ${frappeError.message}`)
    console.error(`Exception: ${frappeError.exception}`)

    // Handle specific error types
    switch (frappeError.exception) {
        case 'ValidationError':
            // Handle validation errors
            break
        case 'PermissionError':
            // Handle permission errors
            break
        case 'DoesNotExistError':
            // Handle not found errors
            break
    }
}

🔧 TypeScript Support

Custom Document Types

import { FrappeDoc } from 'frappe-js-client'

// Define custom document interface
interface Task
    extends FrappeDoc<{
        subject: string
        status: 'Open' | 'In Progress' | 'Completed'
        priority: 'Low' | 'Medium' | 'High'
        assigned_to?: string
        description?: string
        due_date?: string
    }> {}

// Use typed operations
const task = await db.getDoc<Task>('Task', 'TASK-001')
const tasks = await db.getDocList<Task>('Task', {
    filters: [['status', '=', 'Open']],
})

API Response Types

interface LoginResponse {
    message: string
    home_page: string
    user: string
}

const response = await auth.loginWithUsernamePassword<LoginResponse>({
    username: 'admin',
    password: 'password',
})

📖 Examples

Complete Application Example

import { FrappeApp } from 'frappe-js-client'

class TaskManager {
    private app: FrappeApp
    private db: any
    private auth: any

    constructor(frappeUrl: string) {
        this.app = new FrappeApp(frappeUrl)
        this.db = this.app.db()
        this.auth = this.app.auth()
    }

    async initialize() {
        // Authenticate
        await this.auth.loginWithUsernamePassword({
            username: 'admin',
            password: 'password',
        })
    }

    async createTask(subject: string, description?: string) {
        return await this.db.createDoc('Task', {
            subject,
            description,
            status: 'Open',
            priority: 'Medium',
        })
    }

    async getOpenTasks() {
        return await this.db.getDocList('Task', {
            fields: ['name', 'subject', 'status', 'priority'],
            filters: [['status', '=', 'Open']],
            orderBy: { field: 'creation', order: 'desc' },
        })
    }

    async completeTask(taskName: string) {
        return await this.db.updateDoc('Task', taskName, {
            status: 'Completed',
            completed_on: new Date().toISOString(),
        })
    }
}

// Usage
const taskManager = new TaskManager('https://your-frappe-site.com')
await taskManager.initialize()

const newTask = await taskManager.createTask('Implement new feature')
const openTasks = await taskManager.getOpenTasks()
await taskManager.completeTask(newTask.name)

React Hook Example

import { useState, useEffect } from 'react'
import { FrappeApp } from 'frappe-js-client'

const useFrappeClient = (url: string) => {
    const [app] = useState(() => new FrappeApp(url))
    const [isAuthenticated, setIsAuthenticated] = useState(false)

    useEffect(() => {
        const checkAuth = async () => {
            try {
                const auth = app.auth()
                const user = await auth.getLoggedInUser()
                setIsAuthenticated(!!user)
            } catch {
                setIsAuthenticated(false)
            }
        }
        checkAuth()
    }, [app])

    return { app, isAuthenticated }
}

🤝 Contributing

We welcome contributions! Please see our contributing guidelines:

  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

Development Setup

# Clone the repository
git clone https://github.com/dhiashalabi/frappe-js-client.git

# Install dependencies
npm install

# Run tests
npm test

# Build the project
npm run build

# Run linting
npm run lint

📄 License

This project is licensed under the MIT License - see the LICENSE file for details.

🆘 Support


Made with ❤️ by the DHia A. SHalabi