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

thai-smartcard

v1.0.28

Published

High-performance Smart Card Reader library - Native Rust bindings for PC/SC. Supports all smart card types (Thai ID, EMV, etc.)

Readme

thai-smartcard

High-performance Smart Card Reader library for Node.js - Native Rust bindings for PC/SC protocol. Supports all smart card types (Thai ID cards, EMV cards, contactless cards, etc.)

Features

  • 🚀 High Performance - Native Rust implementation
  • 🔌 Universal Support - Works with all PC/SC compatible smart cards
  • 📇 Thai ID Cards - Optimized for Thai national ID cards
  • 💳 EMV Cards - Support for credit/debit cards
  • 🔐 Contactless Cards - NFC/RFID card support
  • 🎯 TypeScript - Full TypeScript support
  • Auto Retry - Built-in retry logic
  • 🔄 GET RESPONSE - Automatic handling of extended data responses

Prerequisites

  • Node.js 14.0 or higher
  • PC/SC Smart Card Service (runtime dependency)
    • macOS/Windows: Pre-installed ✅
    • Linux: Must be installed manually
      # Ubuntu/Debian
      sudo apt-get update
      sudo apt-get install -y pcscd libpcsclite1
      sudo systemctl start pcscd
          
      # Fedora/RHEL/CentOS
      sudo dnf install -y pcsc-lite pcsc-lite-libs
      sudo systemctl start pcscd
          
      # Alpine Linux
      apk add --no-cache pcsc-lite pcsc-lite-dev
    • Docker: Add to Dockerfile:
      RUN apt-get update && apt-get install -y pcscd libpcsclite1
  • Card Reader compatible with PC/SC protocol

Installation

npm install thai-smartcard
# or: yarn add thai-smartcard
# or: bun add thai-smartcard
# or: pnpm add thai-smartcard

Pre-built binaries included - No Rust installation required. Supports macOS (Intel & Apple Silicon), Linux (x64 & ARM64), and Windows (x64 & ARM64).

Quick Start

Basic Usage

import { SmartCardReader, ShareMode, Disposition } from 'thai-smartcard';

const reader = new SmartCardReader();

// List available readers
const readers = reader.listReaders();
console.log('Available readers:', readers);

// Connect to card
const card = reader.connect(readers[0], ShareMode.Shared);

// Transmit APDU command
const result = card.transmit(
  Buffer.from([0x00, 0xA4, 0x04, 0x00, 0x08, 0xA0, 0x00, 0x00, 0x00, 0x54, 0x48, 0x00, 0x01])
);

console.log('Response:', result.data.toString('hex'));
console.log('Status:', result.sw1.toString(16), result.sw2.toString(16));

// Disconnect
card.disconnect(Disposition.LeaveCard);

Reading Thai ID Card

import { SmartCardReader, ShareMode, Disposition } from 'thai-smartcard';

const reader = new SmartCardReader();
const readers = reader.listReaders();

if (readers.length === 0) {
  throw new Error('No card readers found');
}

// Wait for card
const status = await reader.waitForCard(readers[0], 30000);
if (!status.present) {
  throw new Error('No card present');
}

// Connect to card
const card = reader.connect(readers[0], ShareMode.Shared);

try {
  // SELECT Thai ID application
  const selectResult = card.transmit(
    Buffer.from([0x00, 0xA4, 0x04, 0x00, 0x08, 0xA0, 0x00, 0x00, 0x00, 0x54, 0x48, 0x00, 0x01]),
    40
  );

  if (selectResult.sw1 !== 0x90 || selectResult.sw2 !== 0x00) {
    throw new Error('Failed to select application');
  }

  // Read Citizen ID
  const cidResult = card.transmit(
    Buffer.from([0x80, 0xB0, 0x00, 0x04, 0x02, 0x00, 0x0D]),
    40
  );

  const citizenId = cidResult.data.slice(0, 13).toString('ascii');
  console.log('Citizen ID:', citizenId);

  // Read Thai Name
  const nameResult = card.transmit(
    Buffer.from([0x80, 0xB0, 0x00, 0x11, 0x02, 0x00, 0x64]),
    100
  );

  // Parse TIS-620 encoded Thai text
  const nameTh = parseThaiText(nameResult.data);
  console.log('Name (TH):', nameTh);

} finally {
  card.disconnect(Disposition.LeaveCard);
}

With Retry Logic

const result = card.transmitWithRetry(
  Buffer.from([0x00, 0xA4, 0x04, 0x00, 0x08, 0xA0, 0x00, 0x00, 0x00, 0x54, 0x48, 0x00, 0x01]),
  40,
  3,  // max retries
  100 // retry delay (ms)
);

API Reference

SmartCardReader

new SmartCardReader()

// Methods
listReaders(): string[]
getStatus(readerName: string): CardStatus
connect(readerName: string, shareMode?: ShareMode, preferredProtocol?: Protocol): Card
waitForCard(readerName: string, timeoutMs?: number): Promise<CardStatus>

Card

// Methods
getATR(): Buffer | undefined
getStatus(): CardStatus
transmit(command: Buffer, responseLength?: number, maxGetResponse?: number): TransmitResult
transmitWithRetry(command: Buffer, responseLength?: number, maxRetries?: number, retryDelayMs?: number): TransmitResult
disconnect(disposition?: Disposition): void

Types

interface TransmitResult {
  data: Buffer;  // Response data (excluding status word)
  sw1: number;   // Status word byte 1
  sw2: number;   // Status word byte 2
}

interface CardStatus {
  present: boolean;  // Card is present in reader
  empty: boolean;    // Reader slot is empty
  mute: boolean;     // Card is mute (not responding)
  atr?: Buffer;      // ATR (Answer To Reset)
}

enum ShareMode {
  Shared = 0,      // Multiple applications can access
  Exclusive = 1,   // Only this application can access
  Direct = 2,      // Direct access to reader
}

enum Protocol {
  T0 = 0,    // T=0 protocol
  T1 = 1,    // T=1 protocol
  Raw = 2,   // Raw protocol
  Any = 3,   // Any protocol (auto-detect)
}

enum Disposition {
  LeaveCard = 0,    // Leave card in reader
  ResetCard = 1,    // Reset card
  UnpowerCard = 2,  // Unpower card
  EjectCard = 3,    // Eject card
}

Error Handling & Best Practices

The library throws errors for common scenarios (reader not found, card not present, communication errors, timeouts). Always wrap calls in try-catch blocks:

try {
  const card = reader.connect(readerName);
  const result = card.transmit(command);
} catch (error) {
  console.error('Error:', error.message);
}

Performance Tips:

  • Reuse card connection for multiple APDU commands
  • Set appropriate responseLength to avoid unnecessary data
  • Use transmitWithRetry for unreliable cards
  • Monitor card status with waitForCard

Troubleshooting

Error: libpcsclite.so.1: No such file or directory

  • Solution: Install PC/SC libraries (see Prerequisites above)
  • Verify: ldconfig -p | grep pcsclite should show libpcsclite.so.1
  • Docker: Make sure PC/SC libraries are installed in your Docker image

No readers found:

  • Ensure card reader is connected
  • Check PC/SC service is running: sudo systemctl status pcscd (Linux)
  • Start service: sudo systemctl start pcscd

Permission errors (Linux):

sudo usermod -a -G pcscd $USER
# Log out and log back in

License

MIT