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

@graphland/zkteco

v0.1.0

Published

TypeScript client for ZKTeco biometric attendance devices — TCP/UDP protocol, users, attendance logs, real-time events

Readme

@graphland/zkteco

TypeScript client for ZKTeco biometric attendance devices. Connects over TCP (with UDP fallback), supports CommKey authentication, and provides a high-level API for users, attendance, and device management.

Works on Node.js ≥ 18 and Bun — no runtime dependencies.

Installation

npm install @graphland/zkteco
# or
bun add @graphland/zkteco

Ships as ESM with bundled TypeScript declarations. Prefer a GUI? The same engine powers the Graphland ZKT Client desktop app for macOS and Windows.

Quick start

import { ZKTecoClient } from "@graphland/zkteco";

const zk = new ZKTecoClient({
  ip: "192.168.0.153",
  port: 6523,        // device TCP port (default: 4370)
  timeout: 10000,
  commKey: 0,        // device CommKey password (default: 0)
});

await zk.connect();

const info = await zk.getInfo();
console.log(info); // { userCounts, logCounts, logCapacity }

await zk.disconnect();

Configuration

| Option | Default | Description | |--------|---------|-------------| | ip | — | Device IP address (required) | | port | 4370 | TCP port | | timeout | 10000 | Socket timeout in ms | | udpPort | 4000 | Local UDP bind port (fallback) | | commKey | 0 | Communication key set on the device | | openDoorDelaySec | 3 | Door unlock duration |

Connection

  • Tries TCP first, falls back to UDP if TCP is refused.
  • Handles CommKey auth: CMD_ACK_UNAUTHCMD_AUTH handshake (same as pyzk).
  • Validates the device after connect via getInfo().
await zk.connect({
  onError: (err) => console.error(err),
  onClose: (type) => console.log(`Disconnected (${type})`),
});

Users

// List all users
const users = await zk.getUsers();

// Find by id (throws ZkNotFoundError if missing)
const user = await zk.getUserById("5011");

// Search
const results = await zk.searchUsers("rayhan");
const exact = await zk.searchUsers({ userId: "5011", match: "exact" });
const first = await zk.searchUser({ name: "Ray" }); // null if not found

// Create / update / delete
await zk.createUser({ userId: "99", name: "Jane", password: "1234" });
await zk.updateUser("99", { name: "Jane Updated" });
await zk.deleteUser("99"); // or deleteUser(uid)

Attendance

The device returns all attendance logs in one download. Per-user methods filter client-side.

// All records
const all = await zk.getAttendances();

// One user
const records = await zk.getUserAttendances("5011");

// With date range
const june = await zk.getUserAttendances("5011", {
  from: new Date("2026-06-01"),
  to: new Date("2026-06-30"),
});

// Real-time punches
await zk.getRealTimeLogs(({ userId, attTime }) => {
  console.log(userId, attTime);
});

Check-in / check-out

Each record includes punch and punchLabel:

{
  userSn: 6850,
  deviceUserId: "5011",
  recordTime: Date,
  punch: 1,              // 0=out, 1=in, 2=break-out, 3=break-in
  punchLabel: "check-in",
  status: 1,             // verify mode: fingerprint, card, face, …
  statusLabel: "fingerprint",
}
import { isCheckIn, isCheckOut, getPunchLabel } from "@graphland/zkteco";

records.filter((r) => isCheckIn(r.punch!));
records.filter((r) => isCheckOut(r.punch!));

Note: Punch values depend on device function-key configuration. If the device doesn't use in/out keys, punch may always be 0.

| punch | Default label | |---------|---------------| | 0 | check-out | | 1 | check-in | | 2 | break-out | | 3 | break-in | | 4 | overtime-in | | 5 | overtime-out |

Device operations

await zk.getTime();
await zk.setTime(new Date());
await zk.openDoor(5);           // unlock door for 5 seconds
await zk.disableDevice();
await zk.enableDevice();
await zk.refreshData();
await zk.clearAttendanceLog();
await zk.resetDevice(); // wipes users, fingerprints, logs, and settings

Error handling

import { ZkError, ZkNotFoundError, ZkConnectionError } from "@graphland/zkteco";

try {
  await zk.connect();
  await zk.getUserById("missing");
} catch (err) {
  if (err instanceof ZkConnectionError) {
  // Wrong port, CommKey, or unreachable device
    console.error(err.message, err.port);
  } else if (err instanceof ZkNotFoundError) {
    console.error(`${err.resource} ${err.id} not found`);
  } else if (err instanceof ZkError) {
    console.error(err.toast());
  }
}

| Error | When | |-------|------| | ZkConnectionError | Connect fails (wrong port, CommKey, timeout) | | ZkNotFoundError | getUserById, updateUser, deleteUser — user missing | | ZkError | Any other device/command failure |

Low-level API

import { COMMANDS } from "@graphland/zkteco";

const raw = await zk.executeCmd(COMMANDS.CMD_GET_VERSION, "");

Contributing

Development happens in the zk-client-app monorepo (this package lives in packages/zkteco). Requires Bun:

git clone https://github.com/graphland-dev/zk-client-app.git
cd zk-client-app
bun install
bun run test         # unit tests — protocol, auth, search; no hardware required
bun run typecheck

Bug reports and feature requests: GitHub issues.

License

MIT