kofi-q/pcsc-mini
Node.js PC/SC (smart card) bindings for Linux / MacOS / Win32
› 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);
});
}
pcsc-mini
provides NodeJS bindings to native PC/SC (Personal Computer/Smart Card) APIs:
* MacOS has a separate implementation built on the CryptoTokenKit
API.
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.
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) |
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
Required packages:
libpcsclite1
pcscd
sudo apt install libpcsclite1 pcscd
To run the server daemon:
sudo systemctl start pcscd
N/A
:: MacOS and Windows come pre-installed with smart card support. No additional installation needed.
Bun
bun add pcsc-mini
Deno
deno add npm:pcsc-mini
npm
npm i pcsc-mini
pnpm
pnpm add pcsc-mini
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.
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 |
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.
N/A
:: Required MacOS Framework .tbd
s are included in the pcsc
dependency. No additional installation needed.
N/A
:: Required DLLs are shipped with the Zig compiler. No additional installation needed.
This will output an lib/addon.node
file to enable unit testing. Runs automatically when running the unit tests.
zig build
zig build test
zig build test:node -- --watch
zig build test:zig --watch
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
This will output the final NPM package directories to ./zig-out/npm_packages
.
zig build packages