pcsc-mini - v0.1.3
    Preparing search index...

    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);
    });
    }

    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 )1 ☑️
    MacOS N/A ☑️
    Windows2 ☑️ ⬜️

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

    1 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.

    2 Windows support is limited to a few JS runtimes at the moment (Node.js, Bun, Electron). If additional runtimes are needed, please feel free to open an issue to request it.

    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.15.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 .tbds 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
    

    MIT