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

@lstrihic/codekey

v2.0.1

Published

TypeScript client for code-key.com API

Readme

@lstrihic/codekey

TypeScript client for the code-key.com door access control API.

Installation

npm install @lstrihic/codekey

Requirements

  • Node.js 18+
  • TypeScript 5+ (for TypeScript projects)

Quick Start

import { CodeKeyClient } from '@lstrihic/codekey'

const client = new CodeKeyClient(
  process.env.CODEKEY_USERNAME!,
  process.env.CODEKEY_PASSWORD!
)

// List all users
const users = await client.listUsersParsed('account-id')
console.log(users)

// Get single user
const user = await client.getUser('account-id', 'user-id')

// Add new guest
await client.addOrUpdateUser({
  id: 'account-id',
  userStatus: '0',
  userType: '1',
  name: 'Guest Name',
  device: '15666322',
  dateStart: '24.10.2025',
  timeStart: '05:50',
  dateEnd: '26.10.2025',
  timeEnd: '20:30',
  code: '123456',
  note: '',
  mailTrigger: 'false',
  otp: 'false',
  openAPILink: 'uuid',
  importID: '0',
})

AI Agent Usage Guide

This package only manages normal time-bound CodeKey users. Do not use, add, or recreate private/permanent user functionality.

Hard Rules

  • Never call private/permanent endpoints: get_private_users, add_private_job, or del_job.
  • Never add public methods named listPrivateUsers, listPrivateUsersParsed, addPermanentUser, or deletePermanentUser.
  • Never hardcode real credentials, session cookies, account IDs, or access codes in application source. Read credentials from environment variables.
  • Never log passwords, PHPSESSID values, or full raw API responses from authenticated requests.
  • Use deleteUser() only for users returned by listUsersParsed() / get_jobs.

Environment Variables

Required variables:

  • CODEKEY_USERNAME
  • CODEKEY_PASSWORD
  • CODEKEY_ACCOUNT_ID
const client = new CodeKeyClient(
  process.env.CODEKEY_USERNAME!,
  process.env.CODEKEY_PASSWORD!
)

const accountId = process.env.CODEKEY_ACCOUNT_ID!

Safe Normal User Create Flow

Use this flow when an AI agent needs to create a user:

  1. Get existing normal users with listUsersParsed(accountId).
  2. Pick a device from an existing normal user. Do not query private users for devices.
  3. Create the user with addOrUpdateUser().
  4. Re-fetch listUsersParsed(accountId) and find the new user there.
  5. Store the returned groupUserID; this is required for updates and deletion.
import { randomUUID } from 'node:crypto'
import { CodeKeyClient } from '@lstrihic/codekey'

const client = new CodeKeyClient(
  process.env.CODEKEY_USERNAME!,
  process.env.CODEKEY_PASSWORD!
)

const accountId = process.env.CODEKEY_ACCOUNT_ID!
const users = await client.listUsersParsed(accountId)
const device = users[0]?.device

if (!device) {
  throw new Error('No normal user exists to source a device id from')
}

const name = `Guest ${Date.now()}`

await client.addOrUpdateUser({
  id: accountId,
  userStatus: '0',
  userType: '1',
  name,
  device,
  dateStart: '11.05.2026',
  timeStart: '05:50',
  dateEnd: '13.05.2026',
  timeEnd: '20:30',
  code: '123456',
  note: '',
  mailTrigger: 'false',
  otp: 'false',
  openAPILink: randomUUID(),
  importID: '0',
})

const created = (await client.listUsersParsed(accountId)).find(
  (user) => user.name === name
)

if (!created) {
  throw new Error('Created user was not found in the normal user list')
}

addOrUpdateUser() sends import_id: '0' automatically for new users when editing is omitted. Passing importID: '0' explicitly is still recommended in generated examples because it mirrors the browser request.

Safe Update Flow

Update an existing normal user by passing editing with the existing userID.

await client.addOrUpdateUser({
  id: accountId,
  userStatus: existing.userStatus,
  userType: existing.userType,
  name: existing.name,
  device: existing.device,
  dateStart: '11.05.2026',
  timeStart: '05:50',
  dateEnd: '13.05.2026',
  timeEnd: '20:30',
  code: existing.code,
  note: '',
  mailTrigger: 'false',
  otp: 'false',
  openAPILink: existing.openAPILink,
  editing: existing.userID,
})

Safe Delete Flow

Delete only normal users found through listUsersParsed().

const user = (await client.listUsersParsed(accountId)).find(
  (entry) => entry.name === name
)

if (user) {
  await client.deleteUser({
    id: accountId,
    groupUserID: user.groupUserID,
  })
}

Live Test Cleanup Pattern

When an AI agent creates a live user for testing, use a unique name and delete it in finally.

import type { User } from '@lstrihic/codekey'

const name = `TEST_${Date.now()}`
let created: User | undefined

try {
  await client.addOrUpdateUser({ ...request, name, importID: '0' })
  created = (await client.listUsersParsed(accountId)).find(
    (user) => user.name === name
  )
} finally {
  if (created) {
    await client.deleteUser({
      id: accountId,
      groupUserID: created.groupUserID,
    })
  }
}

Formats

  • Dates sent to the API should use DD.MM.YYYY, for example 11.05.2026.
  • Times sent to the API should use HH:MM, for example 05:50.
  • The API may return times as HH:MM or HH:MM:SS; keep them as strings.
  • getUser() handles both JSON and semicolon-delimited responses from CodeKey.

API Reference

Constructor

new CodeKeyClient(username: string, password: string)

Creates a new client instance with automatic authentication and session management.

User Management Methods

listUsers(id: string): Promise<Buffer>

Get all users as raw CSV data.

Parameters:

  • id - Account ID

Returns: Buffer containing CSV response

const rawUsers = await client.listUsers('24E40CAB556911EFA812F2FABB7CF30C')
console.log(rawUsers.toString())

listUsersParsed(id: string): Promise<User[]>

Get all users as parsed objects.

Parameters:

  • id - Account ID

Returns: Array of User objects

const users = await client.listUsersParsed('24E40CAB556911EFA812F2FABB7CF30C')
for (const user of users) {
  console.log(`${user.name} - Code: ${user.code}`)
}

getUser(id: string, userID: string): Promise<UserInfo>

Get detailed info for a single user as a parsed object. The CodeKey endpoint can return either JSON or the same semicolon-delimited format used by the list endpoint; both are handled.

Parameters:

  • id - Account ID
  • userID - User ID

Returns: UserInfo object

const user = await client.getUser('24E40CAB556911EFA812F2FABB7CF30C', '2685015')
console.log(`${user.name}: ${user.dateStart} - ${user.dateEnd}`)

getUserRaw(id: string, userID: string): Promise<Buffer>

Get detailed info for a single user as raw JSON data.

Parameters:

  • id - Account ID
  • userID - User ID

Returns: Buffer containing JSON response

const rawUser = await client.getUserRaw('24E40CAB556911EFA812F2FABB7CF30C', '2685015')

addOrUpdateUser(req: AddOrUpdateUserRequest): Promise<Buffer>

Create or update a temporary user with time restrictions.

Creating a new user: Omit editing. importID defaults to '0', and may also be passed explicitly. Updating existing user: Set editing to user ID and omit importID

Parameters:

  • req - AddOrUpdateUserRequest object

Returns: Buffer containing response

// Create new guest
await client.addOrUpdateUser({
  id: '24E40CAB556911EFA812F2FABB7CF30C',
  userStatus: '0',
  userType: '1',
  name: 'New Guest',
  device: '15666322',
  dateStart: '24.10.2025',
  timeStart: '05:50',
  dateEnd: '26.10.2025',
  timeEnd: '20:30',
  code: '543543',
  note: '',
  mailTrigger: 'false',
  otp: 'false',
  openAPILink: 'uuid',
  importID: '0',
})

// Update existing user
await client.addOrUpdateUser({
  id: '24E40CAB556911EFA812F2FABB7CF30C',
  userStatus: '0',
  userType: '1',
  name: 'Updated Name',
  device: '15666322',
  dateStart: '24.10.2025',
  timeStart: '05:50',
  dateEnd: '30.12.2025',
  timeEnd: '20:30',
  code: '246811',
  note: '',
  mailTrigger: 'false',
  otp: 'false',
  openAPILink: 'uuid',
  editing: '2685015',
})

Access Control Methods

updateAccessPeriod(req: UpdateAccessPeriodRequest): Promise<Buffer>

Update access date range for a user.

Parameters:

  • req - UpdateAccessPeriodRequest object

Returns: Buffer containing response

await client.updateAccessPeriod({
  id: '24E40CAB556911EFA812F2FABB7CF30C',
  groupUserID: 'group-uuid',
  dateStart: '24.10.2025',
  dateEnd: '28.11.2025',
  userID: '2685015',
  actionID: '0',
})

updateAccessCode(req: UpdateAccessCodeRequest): Promise<Buffer>

Update door access code for a user.

Parameters:

  • req - UpdateAccessCodeRequest object

Returns: Buffer containing response

await client.updateAccessCode({
  id: '24E40CAB556911EFA812F2FABB7CF30C',
  groupUserID: 'group-uuid',
  newCode: '246810',
  userID: '2685015',
  actionID: '0',
  name: 'test1',
  currentCode: '246811',
  userType: '1',
})

deleteUser(req: DeleteUserRequest): Promise<Buffer>

Delete a temporary guest user.

Parameters:

  • req - DeleteUserRequest object

Returns: Buffer containing response

await client.deleteUser({
  id: '24E40CAB556911EFA812F2FABB7CF30C',
  groupUserID: 'group-uuid',
})

TypeScript Support

Full TypeScript support with type definitions included.

import type {
  User,
  UserInfo,
  AddOrUpdateUserRequest,
  UpdateAccessPeriodRequest,
  UpdateAccessCodeRequest,
  DeleteUserRequest,
} from '@lstrihic/codekey'

Type Definitions

User - Temporary user with time restrictions

interface User {
  userID: string
  status: string
  userType: string
  name: string
  device: string
  dateStart: string
  timeStart: string
  dateEnd: string
  timeEnd: string
  code: string
  userStatus: string
  deviceName: string
  createdAt: string
  lastAccess: string
  groupUserID: string
  openAPILink: string
}

UserInfo - Detailed user information

interface UserInfo {
  id: string
  groupUserID: string
  userID: string
  status?: string
  name: string
  device?: string
  code: string
  dateStart: string
  timeStart?: string
  dateEnd: string
  timeEnd?: string
  userType: string
  note?: string
  userStatus?: string
  deviceName?: string
  lastAccess?: string
  openAPILink?: string
  actionID: string
  active: boolean
  createdAt?: Date | string
  updatedAt?: Date | string
}

Error Handling

import {
  AuthenticationError,
  RequestError,
  ParseError,
} from '@lstrihic/codekey'

try {
  await client.listUsers('account-id')
} catch (error) {
  if (error instanceof AuthenticationError) {
    console.error('Login failed')
  } else if (error instanceof RequestError) {
    console.error('API request failed:', error.statusCode)
  } else if (error instanceof ParseError) {
    console.error('Response parsing failed')
  }
}

Error Types:

  • AuthenticationError - Login or authentication failed
  • RequestError - API request failed (includes statusCode)
  • ParseError - CSV/JSON parsing failed

Features

  • Automatic authentication and session management
  • Cookie-based session handling with automatic re-authentication
  • Promise-based async operations
  • Full TypeScript support
  • Clean error handling with custom error classes
  • CSV parsing for list operations
  • JSON parsing for detailed user info

Usage in Next.js

// app/api/users/route.ts
import { CodeKeyClient } from '@lstrihic/codekey'
import { NextResponse } from 'next/server'

export async function GET() {
  const client = new CodeKeyClient(
    process.env.CODEKEY_USERNAME!,
    process.env.CODEKEY_PASSWORD!
  )

  try {
    const users = await client.listUsersParsed(process.env.CODEKEY_ACCOUNT_ID!)
    return NextResponse.json(users)
  } catch (error) {
    return NextResponse.json({ error: 'Failed to fetch users' }, { status: 500 })
  }
}

License

MIT

Author

Lovro Strihic