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 🙏

© 2025 – Pkg Stats / Ryan Hefner

nokan-client

v0.3.3

Published

TypeScript SDK with React components for Nokan Taskboard Public API

Downloads

538

Readme

nokan-client

npm version License: MIT

TypeScript SDK with React components for Nokan Taskboard Public API.

Features

  • Full TypeScript support with complete type definitions
  • Standalone API client for any JavaScript/TypeScript project
  • Ready-to-use React components (optional)
  • Built-in error handling with typed errors
  • Rate limiting support
  • Dynamic priorities, columns, and statuses from API
  • Works in Node.js and browser environments

Installation

npm install nokan-client

Quick Start

import { NokanClient } from 'nokan-client';

const client = new NokanClient({
    token: 'nkn_live_xxx', // Get this from Board Settings > API
    baseUrl: 'https://your-app.vercel.app'
});

// Connect and discover board info
const info = await client.connect();
console.log('Connected to board:', info.boardTitle);
console.log('Permissions:', info.permissions);
console.log('Available columns:', info.columns);
console.log('Available priorities:', info.priorities);
console.log('Available statuses:', info.statuses);

// List tickets
const { data: tickets, meta } = await client.listTickets({ page: 1, limit: 20 });
console.log(`Found ${meta.pagination.total} tickets`);

// Create a ticket (column_id is optional - defaults to first column)
const newTicket = await client.createTicket({
    title: 'Bug report',
    description: 'Something is not working correctly',
    priority: 'High' // Use priority label from info.priorities
});

// Add a comment
await client.addComment(newTicket.id, {
    content: 'This needs immediate attention!'
});

API Reference

Constructor

const client = new NokanClient({
    token: string,       // Required: API token from board settings
    baseUrl?: string,    // Optional: API base URL (default: current origin)
    timeout?: number     // Optional: Request timeout in ms (default: 30000)
});

Methods

connect(): Promise<ApiTokenInfo>

Connect to the API and discover board information. Must be called before using other methods.

Returns:

  • boardId - Board UUID
  • boardTitle - Board name
  • permissions - { read, write, delete } booleans
  • columns - Array of { id, title, order }
  • statuses - Array of { id, label, color }
  • priorities - Array of { id, label, color }

getBoard(): Promise<Board>

Get current board information. Requires read permission.

listTickets(options?): Promise<PaginatedResponse<Ticket>>

List tickets with pagination and filtering.

Options:

  • page - Page number (default: 1)
  • limit - Items per page, max 100 (default: 50)
  • column_id - Filter by column
  • status_id - Filter by status
  • completed - Filter by completion status

getTicket(ticketId): Promise<TicketDetail>

Get ticket details including comments and attachments.

createTicket(input): Promise<Ticket>

Create a new ticket. Requires write permission.

Input:

  • title - Required
  • column_id - Optional (defaults to first column/Backlog)
  • description - Optional
  • priority - Priority label (e.g. "High", "Medium") or ID from connect().priorities
  • status_id - Optional

updateTicket(ticketId, input): Promise<Ticket>

Update an existing ticket. Requires write permission.

deleteTicket(ticketId): Promise<void>

Delete a ticket. Requires delete permission.

addComment(ticketId, input): Promise<Comment>

Add a comment to a ticket. Requires write permission.

listComments(ticketId): Promise<Comment[]>

List comments for a ticket. Requires read permission.

addAttachment(ticketId, file, fileName?): Promise<Attachment>

Upload an attachment. Requires write permission. Max 10MB.

listAttachments(ticketId): Promise<Attachment[]>

List attachments for a ticket. Requires read permission.

Error Handling

import {
    NokanClient,
    AuthenticationError,
    PermissionError,
    RateLimitError,
    NotFoundError,
    ValidationError
} from 'nokan-client';

try {
    const ticket = await client.createTicket({ ... });
} catch (error) {
    if (error instanceof AuthenticationError) {
        // Token is invalid or expired
        console.error('Please check your API token');
    } else if (error instanceof PermissionError) {
        // Token doesn't have required permission
        console.error('Missing write permission');
    } else if (error instanceof RateLimitError) {
        // Too many requests
        console.error(`Rate limited. Retry after ${error.retryAfter} seconds`);
    } else if (error instanceof NotFoundError) {
        // Resource not found
        console.error('Ticket not found');
    } else if (error instanceof ValidationError) {
        // Invalid input
        console.error(`Validation error: ${error.message}`);
    }
}

Permissions

When creating a token, you can set these permissions:

| Permission | Allows | |------------|--------| | read | GET endpoints (list, get details) | | write | POST, PUT endpoints (create, update, comments, attachments) | | delete | DELETE endpoints (delete tickets) |

Rate Limiting

Default rate limit is 60 requests per minute per token. When exceeded, the API returns a 429 status with Retry-After header.

The SDK throws a RateLimitError with:

  • retryAfter - Seconds until rate limit resets
  • resetAt - Date when rate limit resets

React Components

The SDK includes ready-to-use React components. React is an optional peer dependency.

TicketForm

Form for creating new tickets. Priorities and columns are automatically loaded from the API.

import { NokanClient, TicketForm } from 'nokan-client';

const client = new NokanClient({ token: 'nkn_live_xxx', baseUrl: '...' });

function App() {
    return (
        <TicketForm
            client={client}
            onSuccess={(ticket) => console.log('Created:', ticket.id)}
            onError={(error) => console.error(error)}
            hideColumn      // Optional: hide column selector (use default)
            hidePriority    // Optional: hide priority selector
            defaultPriority="High" // Optional: set default priority
        />
    );
}

Props:

  • client - NokanClient instance (required)
  • onSuccess - Callback when ticket is created
  • onError - Callback on error
  • hideColumn - Hide column selector (will use first column)
  • hidePriority - Hide priority selector
  • defaultPriority - Default priority label
  • hideAttachment - Hide attachment upload field
  • showAttachment - Show attachment upload field (default: visible)
  • className - CSS class for the form

TicketList

List of tickets with filtering and pagination. Priority colors are automatically loaded from the API.

import { NokanClient, TicketList } from 'nokan-client';

const client = new NokanClient({ token: 'nkn_live_xxx', baseUrl: '...' });

function App() {
    return (
        <TicketList
            client={client}
            onTicketClick={(ticketId) => console.log('Selected:', ticketId)}
        />
    );
}

Props:

  • client - NokanClient instance (required)
  • onTicketClick - Callback when ticket is clicked
  • className - CSS class for the container

TicketView

Ticket details with comments and attachments. Priority colors are automatically loaded from the API.

import { NokanClient, TicketView } from 'nokan-client';

const client = new NokanClient({ token: 'nkn_live_xxx', baseUrl: '...' });

function App() {
    return (
        <TicketView
            client={client}
            ticketId="ticket-uuid-here"
            onClose={() => console.log('Closed')}
            onUpdate={(ticket) => console.log('Updated:', ticket)}
        />
    );
}

Props:

  • client - NokanClient instance (required)
  • ticketId - Ticket UUID (required)
  • onClose - Callback when close button is clicked
  • onUpdate - Callback when ticket is updated (comment/attachment added)
  • className - CSS class for the container

Full Example

import { useState } from 'react';
import { NokanClient, TicketForm, TicketList, TicketView } from 'nokan-client';

const client = new NokanClient({
    token: 'nkn_live_xxx',
    baseUrl: 'https://your-app.vercel.app'
});

function TicketSystem() {
    const [selectedTicket, setSelectedTicket] = useState<string | null>(null);

    return (
        <div style={{ display: 'flex', gap: '24px' }}>
            <div style={{ flex: 1 }}>
                <h2>New Ticket</h2>
                <TicketForm client={client} />

                <h2>Tickets</h2>
                <TicketList
                    client={client}
                    onTicketClick={setSelectedTicket}
                />
            </div>

            {selectedTicket && (
                <div style={{ flex: 1 }}>
                    <TicketView
                        client={client}
                        ticketId={selectedTicket}
                        onClose={() => setSelectedTicket(null)}
                    />
                </div>
            )}
        </div>
    );
}

Changelog

0.3.1

  • Added attachment upload support in TicketForm
  • New props for TicketForm: showAttachment, hideAttachment
  • Multiple file upload with preview and remove functionality

0.3.0

  • Dynamic priorities from API (no more hardcoded values)
  • column_id is now optional in createTicket() - defaults to first column
  • New props for TicketForm: hideColumn, hidePriority, defaultPriority
  • Priority colors in TicketList and TicketView now use API colors
  • connect() returns priorities array

0.2.0

  • Added React components: TicketForm, TicketList, TicketView
  • Package renamed to nokan-client

0.1.0

  • Initial release with core API client

License

MIT