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

@samlab-corp/sfm-node

v0.5.0

Published

SFM Protocol V3.6.0 based fingerprint recognition library for Node.js

Readme

@samlab-corp/sfm-node

Node.js library for Suprema SFM (Suprema Fingerprint Module) devices based on SFM Protocol Manual V3.6.0.

Supports fingerprint enrollment, verification (1:1), identification (1:N), template management, firmware upgrade, and continuous scanning via Serial (RS232), RS422/485, or TCP/IP.

Installation

npm install @samlab-corp/sfm-node
# or
yarn add @samlab-corp/sfm-node

Requirements

  • Node.js 18+
  • A Suprema SFM fingerprint module connected via serial port or TCP/IP

Quick Start

import { SfmCommands } from "@samlab-corp/sfm-node";

// Create and connect in one step
const sfm = await SfmCommands.create({
  portPath: "/dev/ttyUSB0",
  baudRate: 115200,
});

// Enroll fingerprint (userId: 1)
await sfm.fingerprint.enroll(1);

// 1:1 Verification
await sfm.fingerprint.verify(1);

// 1:N Identification
await sfm.fingerprint.identify();

await sfm.disconnect();

Constructor Options

const sfm = new SfmCommands({
  portPath: "/dev/ttyUSB0", // Serial port path (used by create() / connect())
  baudRate: 115200, // Serial baud rate (default: 115200)
  debug: false, // Enable debug logging
  commandTimeout: 20000, // Command response timeout in ms
  readTimeout: 3000, // Data read timeout in ms
  secureMode: false, // AES256 encryption mode
  encryptionKey: Buffer, // AES256 encryption key (32 bytes)
  iv: Buffer, // AES256 IV (16 bytes)
  secureCode: Buffer, // Secure code
  encryptionMode: "AES256_CBC", // Encryption mode ('AES256_CBC' | 'AES256_ECB')
  networkMode: false, // RS422/485 network mode
  terminalId: 0, // Network terminal ID
  hexAsciiMode: false, // Hex-ASCII serial bridge mode
  autoReconnect: {
    // Auto-reconnect options
    enabled: true,
    interval: 3000,
    maxRetries: 10,
  },
});

API Reference

Connection Management

| Method | Description | | ------------------------------------------ | --------------------------------------------- | | SfmCommands.create(options) | Create instance and connect in one step | | SfmCommands.listPorts() | List available serial ports | | sfm.connect(portPath?) | Connect to device (uses portPath from options if omitted) | | sfm.disconnect() | Disconnect from device | | sfm.setSecureMode(enabled, options?) | Toggle AES256 encryption mode | | sfm.setNetworkMode(enabled, terminalId?) | Toggle RS422/485 network mode | | sfm.setOnDisconnect(callback) | Register disconnect callback | | sfm.setAutoReconnect(options) | Configure auto-reconnect | | sfm.setAutoReconnectCallbacks(callbacks) | Register reconnect status callbacks | | sfm.isReconnecting | Whether reconnection is in progress (boolean) |


sfm.fingerprint — Enrollment / Verification / Identification

| Method | Description | Return Type | | ----------------------------------------------------------- | ------------------------------------------------------------------------- | ---------------------------------- | | enroll(userId, flag?, options?) | Enroll fingerprint (auto-adapts to device ENROLL_MODE: 1-scan or 2-scan) | EnrollResult | | enrollScan1(userId, flag?, options?) | First scan enrollment | EnrollResult | | enrollScan2(options?) | Second scan enrollment (for SCAN2 modes) | EnrollResult | | verify(userId, options?) | 1:1 Verification — match against a specific user | VerifyResult | | identify(options?) | 1:N Identification — match against all enrolled fingerprints | IdentifyResult | | deleteTemplate(userId) | Delete a specific user's fingerprint template | CommandResult | | deleteAllTemplates() | Delete all fingerprint templates | CommandResult | | listUserIds(options?) | List enrolled user IDs | ListUserIdsResult | | readTemplate(userId, options?) | Read fingerprint template data from device (RTX protocol) | { success, templateData, error } | | writeTemplate(userId, templateData, flag?, options?) | Write fingerprint template to device (ET protocol, 384B chunks) | { success, userId, error } | | writeTemplateMulti(userId, templateData, flag?, options?) | Write fingerprint template to device (ETX extended protocol, multi-chunk) | { success, userId, error } | | captureImage(options?) | Capture fingerprint image (SI command) | CaptureImageResult |

Enrollment Flags

Flags used with enroll, writeTemplate, etc.:

| Flag | Value | Description | | ----------------------- | ------ | ------------------------------- | | SFM_FLAG.NONE | 0x00 | No flag (default) | | SFM_FLAG.CHECK_ID | 0x70 | Check for duplicate ID | | SFM_FLAG.ADD_NEW | 0x71 | Add fingerprint to existing ID | | SFM_FLAG.AUTO_ID | 0x79 | Auto-assign ID | | SFM_FLAG.CHECK_FINGER | 0x84 | Check for duplicate fingerprint |

Examples

// Basic enrollment
const result = await sfm.fingerprint.enroll(1);

// Enroll with duplicate fingerprint check
const result = await sfm.fingerprint.enroll(1, SFM_FLAG.CHECK_FINGER);

// With log callback
const result = await sfm.fingerprint.verify(1, {
  onLog: (msg) => console.log(msg),
});

// Template backup / restore
const { templateData } = await sfm.fingerprint.readTemplate(1);
await sfm.fingerprint.writeTemplate(2, templateData, SFM_FLAG.ADD_NEW);

// List enrolled users
const list = await sfm.fingerprint.listUserIds();
// { success: true, userIds: [1, 2, 3], count: 3, error: null }

// Capture fingerprint image
const image = await sfm.fingerprint.captureImage();
// { success: true, imageData: Buffer, width: 256, height: 288, error: null }

Return Types

interface EnrollResult {
  success: boolean;
  step: number; // Current scan step (1 or 2)
  userId?: number;
  error?: string;
}

interface VerifyResult {
  success: boolean;
  userId?: number;
  error: string | null;
}

interface IdentifyResult {
  success: boolean;
  userId: number;
  error: string | null;
}

interface ListUserIdsResult {
  success: boolean;
  userIds: number[];
  count: number; // Number of enrolled templates
  error: string | null;
}

interface CaptureImageResult {
  success: boolean;
  imageData: Buffer | null;
  width: number;
  height: number;
  error: string | null;
}

sfm.system — System Configuration / Diagnostics

| Method | Description | Return Type | | ------------------------------- | ------------------------------------------------------------- | ------------------------------------------------------- | | getSystemStatus() | Get module and sensor status | SystemStatusResult | | getDeviceInfo() | Get firmware version, build number, serial number | { firmwareVersion, buildNumber, serialNumber, error } | | getParam(key) | Read system parameter | ParamResult | | setParam(key, value) | Write system parameter (RAM only) | CommandResult | | writeConfig(key, value) | Write system parameter + save to flash (setParam + saveParam) | CommandResult | | saveParam() | Save current parameters to flash | CommandResult | | reset() | Reset module | CommandResult | | selfTest(command?, dataSize?) | Communication self-test (data round-trip verification) | SelfTestResult |

Examples

// Device info
const info = await sfm.system.getDeviceInfo();
// { firmwareVersion: '3.10', buildNumber: '19.7.9.32', serialNumber: 12345, error: null }

// System status
const status = await sfm.system.getSystemStatus();
// { success: true, moduleStatusLabel: 'ALIVE', sensorStatusLabel: 'ALIVE', ... }

// Read parameter
const param = await sfm.system.getParam("SECURITY_LEVEL");
// { value: 0x33, error: null }

// Write parameter (string alias or numeric value)
await sfm.system.setParam("SECURITY_LEVEL", "HIGH");
await sfm.system.saveParam();

// Or use writeConfig to write + save in one call
await sfm.system.writeConfig("ENROLL_MODE", "SCAN2_MERGE");

// Self-test
const test = await sfm.system.selfTest();
// { success: true, sent: 65536, received: 65536, elapsed: 1200, error: null }

Return Types

interface SystemStatusResult {
  success: boolean;
  moduleStatus?: number; // 0x30=ALIVE, 0x34=BUSY
  moduleStatusLabel?: string;
  sensorStatus?: number; // 0x30=ALIVE, 0x31=ERROR
  sensorStatusLabel?: string;
  error: string | null;
}

interface ParamResult {
  value: number;
  error: string | null;
}

interface CommandResult {
  success: boolean;
  error: string | null;
}

interface SelfTestResult {
  success: boolean;
  sent: number;
  received: number;
  elapsed: number; // ms
  error: string | null;
}

sfm.freeScan — Continuous Fingerprint Scanning Mode

The device automatically scans fingerprints and delivers identification results via callback.

| Method | Description | Return Type | | -------------------------- | ---------------------------------------------------------- | ---------------------- | | start(onResult, onLog?) | Start FreeScan (auto-configures AUTO_RESPONSE + FREE_SCAN) | { success, message } | | stop() | Stop FreeScan | { success, message } | | isRunning | Whether FreeScan is active (boolean) | — | | isDeviceFreeScanActive() | Check if device FREE_SCAN parameter is ON | boolean | | onDataHandler(handler) | Register external data handler | — | | offDataHandler() | Remove external data handler | — | | onErrorHandler(handler) | Register external error handler | — | | offErrorHandler() | Remove external error handler | — |

Examples

// Start FreeScan
await sfm.freeScan.start(
  (result) => {
    if (result.success) {
      console.log(`Identified user: ${result.userId}`);
    } else {
      console.log("Unregistered fingerprint");
    }
  },
  (msg) => console.log(msg), // Log callback (optional)
);

// Check status
console.log(sfm.freeScan.isRunning); // true

// Stop FreeScan
await sfm.freeScan.stop();

Callback Types

interface FreeScanResult {
  success: boolean;
  userId?: number; // User ID on successful identification
  flag?: number; // Error flag on failure
}

type FreeScanCallback = (result: FreeScanResult) => void;

sfm.firmware — Firmware Upgrade

| Method | Description | | ---------------------------------------------------- | ---------------------------------------- | | upgrade(filePath, options?) | Firmware upgrade via serial handshake | | upgradeViaProtocol(filePath, chunkSize?, options?) | Firmware upgrade via SFM packet protocol | | loadFirmware(filePath) | Load firmware file and build packet |

Examples

// Serial handshake method (typical)
await sfm.firmware.upgrade("/path/to/firmware.bin", {
  onProgress: (percent, sent, total) => console.log(`${percent}%`),
  onStatus: (msg) => console.log(msg),
});

// Protocol method
await sfm.firmware.upgradeViaProtocol("/path/to/firmware.bin");

Options Type

interface FirmwareOptions {
  onProgress?: (percent: number, sent: number, total: number) => void;
  onStatus?: (message: string) => void;
}

sfm.data — Multi-Packet Data Transfer

Low-level multi-packet data transfer. Handles checksum verification and AES256 encryption automatically.

| Method | Description | | ------------------------------------------- | ------------------------- | | send(command, data, chunkSize?, options?) | Send multi-packet data | | recv(command, totalSize, options?) | Receive multi-packet data |

await sfm.data.send(command, buffer, 0x4000, {
  onProgress: (packetIndex, totalPackets) => { ... },
});

const data = await sfm.data.recv(command, totalSize);

System Parameter Key Reference

Keys and available values for sfm.system.getParam(key), sfm.system.setParam(key, value), and sfm.system.writeConfig(key, value).

Timeout / Timing

| Key | Description | Values | | ------------------ | -------------------------------------- | ------------------------------------------------------------------------------- | | TIMEOUT | Fingerprint input wait time | 'INFINITE', '1S', '2S', '3S', '4S', '5S', '10S', '15S', '20S' | | MATCHING_TIMEOUT | Matching timeout | 'INFINITE', '1S', '3S', '5S', '10S', '20S' | | RESPONSE_DELAY | Response delay | 'NONE', '20MS', '40MS', '60MS', '80MS', '100MS', '200MS' | | FREE_SCAN_DELAY | FreeScan consecutive recognition delay | 'NONE', '1S', '2S', '3S', '5S', '10S' |

Enrollment / Authentication

| Key | Description | Values | | --------------------- | -------------------------------------- | ----------------------------------------------------------------------------------------------------- | | ENROLL_MODE | Enrollment mode | 'SCAN1' (single scan), 'SCAN2_MERGE' (2 scans merged), 'SCAN2_DUAL' (2 scans stored separately) | | SECURITY_LEVEL | Security level (FAR) | 'LOW', 'NORMAL', 'HIGH', 'HIGHEST', 'AUTO_NORMAL', 'AUTO_SECURE', 'AUTO_MORE_SECURE' | | ENROLL_DISPLACEMENT | Finger displacement during enrollment | 'NONE', '1MM', '3MM', '5MM', '10MM' | | PROVISIONAL_ENROLL | Provisional enrollment mode | 'PERMANENT', 'TEMPORARY' | | PASS_WHEN_EMPTY | Authentication result when DB is empty | 'FAIL', 'PASS' |

Sensor / Image

| Key | Description | Values | | -------------------- | --------------------------- | ---------------------------------------------------------------- | | SENSOR_TYPE | Sensor type (read-only) | 'FC', 'OPTICAL', 'TC', 'OC', 'OL', 'FOH02', 'TS4' | | SENSITIVITY | Sensor sensitivity | 'LV0' ~ 'LV7' | | IMAGE_FORMAT | Image transfer format | 'RAW_GRAY', 'BINARY', 'GRAY_4BIT', 'WSQ' | | IMAGE_QUALITY | Image quality threshold | 'WEAK', 'MODERATE', 'STRONG', 'STRONGEST' | | ROTATE_IMAGE | Sensor image rotation | 'NORMAL', 'FLIP' | | ROTATION | Matching rotation tolerance | 'DEG15', 'DEG30', 'DEG45', 'DEG60', 'DEG75', 'DEG90' | | LIGHTING_CONDITION | Lighting environment | 'OUTDOOR', 'INDOOR' |

Communication

| Key | Description | Values | | ------------------- | -------------------------- | ----------------------------------------------------------------------------------------- | | BAUDRATE | Baud rate | '9600', '19200', '38400', '57600', '115200', '230400', '460800', '921600' | | ENCRYPTION_MODE | Encryption mode | 'OFF', 'ON' | | ASCII_PACKET | Packet exchange format | 'HEX', 'ASCII' | | NETWORK_MODE | Network communication mode | 'SINGLE', 'NETWORK' | | SEND_SCAN_SUCCESS | Send SCAN_SUCCESS response | 'OFF', 'ON' |

Operation Mode

| Key | Description | Values | | --------------- | --------------------------- | ------------------------------------------------- | | FREE_SCAN | Idle-state auto scan | 'OFF', 'ON' | | AUTO_RESPONSE | GPIO/FreeScan auto response | 'OFF', 'HOST', 'AUX', 'BOTH' | | FAST_MODE | 1:N matching speed boost | 'OFF', 'LV1' ~ 'LV4', 'FASTEST', 'AUTO' | | WATCHDOG | Watchdog timer | 'OFF', 'ON' |

Template / Security

| Key | Description | Values | | -------------------------- | ---------------------------- | ----------------------------------------- | | TEMPLATE_TYPE | Template type | 'SUPREMA', 'ISO', 'ANSI' | | ENHANCED_PRIVACY | Enhanced privacy mode | 'OFF', 'ON' | | FAKE_FINGER_DETECTION | Fake finger detection | 'OFF', 'WEAK', 'NORMAL', 'STRONG' | | CHECK_LATENT_FINGERPRINT | Latent fingerprint detection | 'ENROLL_ONLY', 'NEVER', 'ALWAYS' |

Read-Only Parameters

| Key | Description | | ------------------ | ------------------------------------- | | TEMPLATE_SIZE | Template size | | MODULE_ID | Module ID | | FIRMWARE_VERSION | Firmware version | | SERIAL_NUMBER | Serial number | | BUILD_NUMBER | Build number | | ENROLLED_FINGER | Number of enrolled fingerprints | | AVAILABLE_FINGER | Number of available fingerprint slots | | BAUDRATE2 | Secondary baud rate | | VOLTAGE_WARNING | Voltage warning threshold | | POWER_OFF | Auto power-off timeout |


Error Codes

| Code | Value | Description | | ------------------------ | ------ | ------------------------------------ | | SFM_ERROR.SUCCESS | 0x61 | Success | | SFM_ERROR.SCAN_SUCCESS | 0x62 | Scan success (intermediate response) | | SFM_ERROR.SCAN_FAIL | 0x63 | Scan failed | | SFM_ERROR.NOT_FOUND | 0x69 | Data not found | | SFM_ERROR.NOT_MATCH | 0x6a | Mismatch | | SFM_ERROR.TRY_AGAIN | 0x6b | Retry needed (poor image quality) | | SFM_ERROR.TIME_OUT | 0x6c | Timeout | | SFM_ERROR.MEM_FULL | 0x6d | Memory full | | SFM_ERROR.EXIST_ID | 0x6e | ID already exists | | SFM_ERROR.CONTINUE | 0x74 | Continue data transfer | | SFM_ERROR.UNSUPPORTED | 0x75 | Unsupported command |

TypeScript

All types are exported:

import type {
  SfmClientOptions,
  EnrollResult,
  VerifyResult,
  IdentifyResult,
  CommandResult,
  ListUserIdsResult,
  CaptureImageResult,
  SystemStatusResult,
  ParamResult,
  SelfTestResult,
  FreeScanResult,
  FreeScanCallback,
  FirmwareOptions,
} from "@samlab-corp/sfm-node";

License

MIT