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

@jx_code/rsimzo-client

v0.0.68

Published

A typed JavaScript/TypeScript client for the [RS-IMZO](https://rs-imzo.uz) digital signature service. Opens a secure popup for authentication, signing, and certificate retrieval — all communication happens via `postMessage` with strict origin validation.

Readme

@jx_code/rsimzo-client

A typed JavaScript/TypeScript client for the RS-IMZO digital signature service. Opens a secure popup for authentication, signing, and certificate retrieval — all communication happens via postMessage with strict origin validation.

Installation

# npm
npm install @jx_code/rsimzo-client

# pnpm
pnpm add @jx_code/rsimzo-client

# yarn
yarn add @jx_code/rsimzo-client

Testing

A staging environment is available at https://stage.rs-imzo.uz where you can create and test EDS (electronic digital signature) keys without affecting production data. Use this server during development by setting targetOrigin:

const client = new RsimzoClient({
  publicKey: 'your-public-key',
  targetOrigin: 'https://stage.rs-imzo.uz',
})

Quick start

import { RsimzoClient } from '@jx_code/rsimzo-client'

const client = new RsimzoClient({ publicKey: 'your-public-key' })

// Fetch certificates
const { data, error } = await client.fetchCertificates()
if (error) {
  console.error(error.errorMessage)
} else {
  console.log('Certificates:', data)
}

Constructor

new RsimzoClient(options: RsOptions)

RsOptions

| Property | Type | Required | Default | Description | |----------|------|----------|---------|-------------| | publicKey | string | Yes | — | Your RS-IMZO public key | | locale | Locale | No | 'uz' | UI language of the popup | | targetOrigin | string | No | 'https://rs-imzo.uz' | Origin of the RS-IMZO service | | storage | RsStorageInput | No | undefined | Persist certificates after fetchCertificates(). See Certificate storage |

const client = new RsimzoClient({
  publicKey: 'your-public-key',
  locale: 'ru',
  storage: true,
})

Methods

fetchCertificates(options?)

Opens a popup to retrieve the user's available certificates. If storage is configured, persists the result automatically.

client.fetchCertificates(options?: RsCertificatesOptions): Promise<RsPostMessageResult<RsSignatureInfo[] | null>>
const { data, error } = await client.fetchCertificates()

if (error) {
  console.error(`[${error.errorCode}] ${error.errorMessage}`)
} else {
  console.log('Certificates:', data)
}

getCertificates()

Reads persisted certificates from the configured storage synchronously. Returns an empty array if storage is not configured, nothing is stored, or the stored data is corrupt.

client.getCertificates(): RsSignatureInfo[]
const certs = client.getCertificates()
// always an array, never null

removeCertificate(serial)

Removes a single certificate from storage by serial number.

client.removeCertificate(serial: string): void

removeAllCertificates()

Clears all persisted certificates from storage.

client.removeAllCertificates(): void

sign(serialNumber?, content?, options?)

Opens a popup to sign content or authenticate with a certificate. The mode option switches between the two operations.

client.sign(
  serialNumber?: string,
  content?: string,
  options?: RsSignOptions
): Promise<RsPostMessageResult<string | null>>

| Parameter | Type | Description | |-----------|------|-------------| | serialNumber | string | Certificate serial number from RsSignatureInfo.serial. Omit to let the popup handle selection | | content | string | The data to sign (Base64 encoded). Omit for auth mode | | options.locale | Locale | Override locale for this call | | options.mode | 'sign' \| 'auth' | 'sign' (default) for signing, 'auth' for authentication | | options.filter | RsCertificateFilter | Pre-filter which certificates are shown in the popup |

// Sign a document
const { data, error } = await client.sign(cert.serial, btoa('content to sign'))

if (error) {
  console.error(`[${error.errorCode}] ${error.errorMessage}`)
} else {
  console.log('Signature:', data)
}

// Authenticate
const { data, error } = await client.sign(cert.serial, undefined, { mode: 'auth' })

// Sign without pre-selecting a certificate (popup handles selection)
const { data, error } = await client.sign(undefined, btoa('content'))

Certificate filters

fetchCertificates() and sign() both accept a filter option to restrict which certificates are shown in the popup.

RsCertificateFilter

| Property | Type | Description | |----------|------|-------------| | serial | string[] | Show only certificates with these serial numbers | | pin | string[] | Show only certificates matching these PINs | | tin | string[] | Show only certificates matching these TINs | | isLegalEntity | boolean | Filter by legal entity status | | isIndividual | boolean | Filter by individual status |

// Fetch only legal entity certificates
await client.fetchCertificates({
  filter: { isLegalEntity: true }
})

// Sign with a specific set of allowed serials
await client.sign(undefined, btoa(content), {
  filter: { serial: ['ABC123', 'DEF456'] }
})

// Filter by TIN
await client.fetchCertificates({
  filter: { tin: ['123456789'] }
})

Certificate storage

Pass storage in the constructor to automatically persist certificates after each successful fetchCertificates() call.

Shorthand

// localStorage, key: 'rsimzo_certificates'
const client = new RsimzoClient({ publicKey: '...', storage: true })

// disabled (default)
const client = new RsimzoClient({ publicKey: '...' })

Full config (RsStorage)

| Property | Type | Default | Description | |----------|------|---------|-------------| | type | StorageType | 'localStorage' | Where to persist: 'localStorage', 'sessionStorage', or 'cookies' | | key | string | 'rsimzo_certificates' | Storage key / cookie name | | cookie | RsCookieOptions | {} | Cookie-specific options. Only used when type is 'cookies' |

// sessionStorage
const client = new RsimzoClient({
  publicKey: '...',
  storage: { type: 'sessionStorage', key: 'my_certs' },
})

// Cookie with expiry
const client = new RsimzoClient({
  publicKey: '...',
  storage: {
    type: 'cookies',
    key: 'my_certs',
    cookie: {
      expires: 7,       // days; omit for session cookie
      path: '/',
      secure: true,
      sameSite: 'Lax',
    },
  },
})

RsCookieOptions

| Property | Type | Default | Description | |----------|------|---------|-------------| | expires | number \| Date | session | Days until expiry (number) or an absolute Date | | path | string | '/' | Cookie path | | domain | string | — | Cookie domain | | secure | boolean | false | Adds the Secure flag | | sameSite | 'Strict' \| 'Lax' \| 'None' | — | SameSite policy |


Result type

All async methods return RsPostMessageResult<T> — a discriminated union:

type RsPostMessageResult<T> =
  | { data: T;    error: null }
  | { data: null; error: RsPostMessageError }

Because it is discriminated, TypeScript narrows the type after checking error:

const result = await client.fetchCertificates()

if (result.error) {
  // result.data is null, result.error is RsPostMessageError
  console.error(result.error.errorMessage)
} else {
  // result.data is RsSignatureInfo[], result.error is null
  console.log(result.data)
}

RsPostMessageError

| Property | Type | Description | |----------|------|-------------| | errorCode | number | Numeric error code (see table below) | | errorMessage | string | Human-readable description | | rawError | unknown | Original error from the service, if any |

Error codes

| Code | Description | |------|-------------| | 13 | Incorrect password | | 10001 | User closed the popup | | 10002 | Failed to fetch token | | 10003 | Operation completed with no result | | 10004 | Certificate not found | | 10005 | Failed to validate client origin | | 10006 | Invalid parameters received by popup | | 10007 | Failed to fetch timestamp | | 10008 | Operation timed out (60 s) | | 10009 | Popup blocked by the browser | | 10010 | Another operation is already in progress |


Types reference

RsSignatureInfo

| Property | Type | Description | |----------|------|-------------| | uid | string | Unique identifier | | serial | string | Certificate serial number — pass to sign() | | label | string | Display label | | fullName | string | Certificate holder full name | | createdAt | number | Issue timestamp (Unix seconds) | | expireAt | number | Expiry timestamp (Unix seconds) | | country | string | Country code | | orgName | string? | Organisation name (legal entities) | | pin | string? | Personal identification number | | tin | string? | Tax identification number | | isLegalEntity | boolean | Whether the certificate belongs to a legal entity | | isExpired | boolean | Whether the certificate is past its expiry date |

Locale

type Locale = 'uz' | 'ru' | 'en'

StorageType

type StorageType = 'localStorage' | 'sessionStorage' | 'cookies'

Concurrency

RsimzoClient allows only one popup operation at a time. Calling sign() or fetchCertificates() while another is already in progress immediately returns an error with code 10010.


Vue 3 example

import { ref, onMounted } from 'vue'
import { RsimzoClient } from '@jx_code/rsimzo-client'
import type { RsSignatureInfo } from '@jx_code/rsimzo-client'

const client = new RsimzoClient({
  publicKey: import.meta.env.VITE_RS_IMZO_PUBLIC_KEY,
  targetOrigin: import.meta.env.VITE_RS_IMZO_TARGET_ORIGIN,
  storage: true,
})

const certificates = ref<RsSignatureInfo[]>([])
const loading = ref(false)

onMounted(() => {
  certificates.value = client.getCertificates()
})

async function loadCertificates() {
  loading.value = true
  const result = await client.fetchCertificates()
  loading.value = false

  if (!result.error) {
    certificates.value = result.data ?? []
  }
}

async function signDocument(serial: string, content: string) {
  const result = await client.sign(serial, btoa(content))

  if (!result.error) {
    console.log('Signature:', result.data)
  }
}

Browser requirements

The client uses window.open() to open a popup and window.postMessage for secure cross-origin communication. Ensure your deployment does not block popups — inform users to allow popups for your domain if the browser blocks them (error code 10009).