pcsc-mini
TypeScript icon, indicating that this package has built-in type declarations

0.1.2 • Public • Published

pcsc-mini • NPM Version

› NodeJS PC/SC API bindings for smart card access on Linux / MacOS / Win32

Docs ↗ | | Overview | | Prerequisites | | Installation | | Usage

import * as pcsc from "pcsc-mini";
const { CardDisposition, CardMode, ReaderStatus } = pcsc;

const client = new pcsc.Client()
  .on("reader", onReader)
  .start();

function onReader(reader: pcsc.Reader) {
  reader.on("change", async status => {
    if (!status.has(ReaderStatus.PRESENT)) return;
    if (status.hasAny(ReaderStatus.MUTE, ReaderStatus.IN_USE)) return;

    const card = await reader.connect(CardMode.SHARED);
    console.log(`${await card.state()}`);

    const resTx =  await card.transmit(
      Uint8Array.of(0xca, 0xfe, 0xf0, 0x0d)
    );
    console.log(resTx);

    const codeFeatures = pcsc.controlCode(3400);
    const features = await card.control(codeFeatures);
    console.log(features);

    await card.disconnect(CardDisposition.RESET);
    client.stop();
    process.exit(0);
  });
}

Overview

pcsc-mini provides NodeJS bindings to native PC/SC (Personal Computer/Smart Card) APIs:

* MacOS has a separate implementation built on the CryptoTokenKit API.

Supported Platforms

Pre-built binary packages are available for the following targets.

These are installed as optional dependencies of the main pcsc-mini package (e.g. @pcsc-mini/linux-x86_64-gnu).

OS arm64 x86 x86_64
Linux ( gnu ) ☑️
Linux ( musl )* ☑️
MacOS N/A ☑️
Windows ☑️ ⬜️

✅ Tested & verified  •  ☑️ Not tested  •  ⬜️ Not available

* During testing on Alpine, the PCSC server daemon needed to be started after a reader was connected for detection/monitoring to work and required a restart whenever a reader was disconnected and reconnected.

JS Runtime Compatibility

Runtime Supported Versions
NodeJS v16.x.x, v18.x.x, v20.x.x, v22.x.x v24.x.x
OTHERS:
Bun Tested with v1.2.12 (may work with earlier)
Deno Tested with v2.3.1 (may work with earlier)
Electron v15.0.0+ (Tested up to v36.2.0)

Prerequisites

Linux - Alpine

Required packages:

  • ccid
  • pcsc-lite
  • pcsc-lite-libs
doas apk add ccid pcsc-lite pcsc-lite-libs

To run the server daemon:

doas rc-service pcscd start

Linux - Debian/Ubuntu/etc

Required packages:

  • libpcsclite1
  • pcscd
sudo apt install libpcsclite1 pcscd

To run the server daemon:

sudo systemctl start pcscd

MacOS/Windows

N/A :: MacOS and Windows come pre-installed with smart card support. No additional installation needed.


Installation

Bun

bun add pcsc-mini

Deno

deno add npm:pcsc-mini

npm

npm i pcsc-mini

pnpm

pnpm add pcsc-mini

Usage

import * as pcsc from "pcsc-mini";
const { CardDisposition, CardMode, ReaderStatus } = pcsc;

// The `Client` emits a "reader" event for each detected device.
const client = new pcsc.Client()
  .on("reader", onReader)
  .on("error", onError)
  .start();

function onError(err: pcsc.Err) {
  console.error("Unexpected PCSC error:", err);
  client.stop();

  // [ Log and exit / attempt `start()` retries with backoff / etc... ]
};

function onReader(reader: pcsc.Reader) {
  let card: pcsc.Card | undefined;

  console.log(`Reader detected: ${reader}`);

  // Each reader emits a "change" event on every reader state change.
  reader.on("change", async status => {
    if (status.hasAny(ReaderStatus.MUTE, ReaderStatus.IN_USE)) return;

    if (!status.has(ReaderStatus.PRESENT)) {
      void card?.disconnect(CardDisposition.RESET);
      card = undefined;
      return;
    }

    try {
      if (!card) card = await reader.connect(CardMode.SHARED);

      // Transmit Uint8Array (or NodeJS Buffer) data:
      const res = await card.transmit(
        Uint8Array.of(0xca, 0xfe, 0xf0, 0x0d)
      );

      // Use Uint8Array response directly, or via DataView/Buffer:
      const vw = new DataView(res.buffer, res.byteOffset, res.length);
      const tag = vw.getUint8(0);
      const len = vw.getUint16(2);
      const val = new Uint8Array(res.buffer, 4, len);

      // ...
    } catch (err) {
      console.error("Card error:", err);
    }
  });

  // "disconnect" is emitted when a reader is no longer detected.
  //
  // All event listeners will be removed from the now-invalid reader.
  // Any reader/card-related state should be disposed of here.
  reader.on("disconnect", async () => {
    void card?.disconnect(CardDisposition.RESET);
    card = undefined;
  });
}

[!TIP]

See the E2E test application for more involved usage and error handling.

Development

Prerequisites

Minimum Version Recommended Version
Zig v0.14.1 See .zigversion
NodeJS v24.0.0 See .nvmrc
pnpm v10.0.0 See package.json
OPTIONAL:
Bun v1.2.12
Deno v2.3.1

Linux

See Prerequisites section above for a list of runtime prerequisites.

Other relevant development libraries (e.g. libpcsclite-dev on Debian-based distros) are included in the pcsc dependency. No additional installation needed.

MacOS

N/A :: Required MacOS Framework .tbds are included in the pcsc dependency. No additional installation needed.

Windows

N/A :: Required DLLs are shipped with the Zig compiler. No additional installation needed.

Building & Testing

Building the dev addon binary:

This will output an lib/addon.node file to enable unit testing. Runs automatically when running the unit tests.

zig build

Running Zig and NodeJS unit tests:

zig build test
Or individually:
zig build test:node -- --watch
zig build test:zig --watch

Running the E2E test application:

This enables testing basic operations against real devices (supporting up to 4 simultaneously connected readers) to verify functionality not testable via unit tests.

zig build e2e

Generating the NPM packages:

This will output the final NPM package directories to ./zig-out/npm_packages.

zig build packages

License

MIT

Package Sidebar

Install

npm i pcsc-mini

Weekly Downloads

96

Version

0.1.2

License

MIT

Unpacked Size

63.9 kB

Total Files

13

Last publish

Collaborators

  • pcsc-mini
  • kofi-q