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

@credenceid/verifier-sdk

v0.1.10

Published

TypeScript SDK for Credence ID verification orchestration

Readme

@credenceid/verifier-sdk

TypeScript SDK for the Credence ID Verification Orchestrator. Add identity verification to any web or Node.js application in minutes.

Installation

npm install @credenceid/verifier-sdk

Quick start (browser)

import { CredenceVerifier } from '@credenceid/verifier-sdk'

const verifier = new CredenceVerifier({ baseUrl: 'https://your-instance.credenceid.com' })

// 1. Activate with your license credentials
await verifier.activate({
  licenseKey: 'CS-your-license-key',
  profileId: 'your-profile-uuid',
})

// 2. Create a verification session
const session = await verifier.createVerificationSession({ purpose: 'age_check' })

// 3. Render the QR code into a container element
const qr = verifier.renderQRCode(session.qrImageBase64, '#qr-container')

// 4. Subscribe to the result (fires automatically when the user completes verification)
const unsubscribe = await verifier.subscribeToVerificationResult(session.sessionId, result => {
  console.log(result.status)    // 'verified' | 'denied' | 'failed' | 'expired' | 'cancelled'
  console.log(result.decision)  // 'verified' (when status === 'verified')
  qr.remove()      // remove QR from DOM
  unsubscribe()    // close SSE connection
})

// 5. Cancel if the user leaves (optional)
await verifier.cancelVerificationSession(session.sessionId)

Server-side (webhook) usage

For server-side integrations, use webhookUrl during activation. The Orchestrator will POST the VerificationResult to your endpoint whenever a session reaches a terminal state.

// Activate with a webhook URL
await verifier.activate({
  licenseKey: 'CS-your-license-key',
  profileId: 'your-profile-uuid',
  webhookUrl: 'https://your-server.com/webhooks/verification',
})

const session = await verifier.createVerificationSession({
  purpose: 'identity_check',
  referenceId: 'POS-TXN-00042',  // optional: your internal reference
})

Your webhook endpoint will receive a POST with the following body:

{
  "sessionId": "aaaabbbb-cccc-dddd-eeee-ffff00001111",
  "status": "verified",
  "purpose": "identity_check",
  "decision": "verified",
  "verifiedAt": 1716734400000
}

Webhook signature verification

Every webhook POST from the Orchestrator includes an X-Credence-Signature header containing an HMAC-SHA256 signature of the request body. Always verify this signature before processing the payload.

import { verifyWebhookSignature } from '@credenceid/verifier-sdk'

// Express.js example — use express.raw() to get the raw body buffer
app.post('/webhooks/verification', express.raw({ type: 'application/json' }), async (req, res) => {
  const signature = req.headers['x-credence-signature'] as string
  const rawBody = req.body.toString('utf8')

  const isValid = await verifyWebhookSignature(
    rawBody,
    signature,
    process.env.CREDENCE_WEBHOOK_SECRET, // same value as JWT_SIGNING_SECRET on the server
  )

  if (!isValid) {
    return res.status(401).json({ error: 'Invalid signature' })
  }

  const result = JSON.parse(rawBody)
  // result.sessionId, result.status, result.decision, result.verifiedAt

  res.sendStatus(200)
})

verifyWebhookSignature() works in both browser (Web Crypto API) and Node.js environments. It uses constant-time comparison to prevent timing attacks.

Server-side integration patterns

There are three ways to receive a verification result. Choose based on your environment:

1. Browser — SSE (recommended for web POS UIs)

subscribeToVerificationResult() automatically uses SSE when window is defined. No extra configuration needed — this is the quick-start example above.

Latency: near-instant (server push).

2. Node.js server — webhook (recommended for server-side backends)

Register a webhookUrl at activation. The Orchestrator POSTs the VerificationResult directly to your server when the session reaches a terminal state. No long-lived connection required.

await verifier.activate({
  licenseKey: 'CS-your-license-key',
  profileId: 'your-profile-uuid',
  webhookUrl: 'https://your-server.com/webhooks/verification',  // HTTPS required
})

const session = await verifier.createVerificationSession({ purpose: 'age_check' })
// The Orchestrator will POST to your webhookUrl when the session completes.
// Your server does not need to call subscribeToVerificationResult().

Verify the X-Credence-Signature header on every incoming webhook (see the webhook signature verification section above).

Latency: near-instant (server push). Preferred over polling for server-side backends.

3. Node.js server — polling fallback (last resort)

If your server-side code cannot accept inbound webhook POSTs (e.g. local development behind NAT, or a serverless function with no public URL), subscribeToVerificationResult() will automatically fall back to polling when running in Node.js (typeof window === 'undefined').

// No webhookUrl registered — SDK falls back to polling automatically
await verifier.activate({ licenseKey: 'CS-your-license-key', profileId: 'your-profile-uuid' })
const session = await verifier.createVerificationSession({ purpose: 'age_check' })

const unsubscribe = await verifier.subscribeToVerificationResult(session.sessionId, result => {
  console.log(result.status)   // 'verified' | 'denied' | 'failed' | 'expired' | 'cancelled'
  console.log(result.decision) // 'verified' when status is 'verified'
  unsubscribe()
})

The interface is identical to the SSE path — the same unsubscribe function is returned. The SDK polls GET /v1/orchestrator/sessions/{id} every 2 seconds until a terminal state is received or unsubscribe() is called.

Latency: up to 2 s (one polling interval). Use webhook instead whenever your server is publicly reachable.


Poll session status

Use getVerificationStatus() to manually check the current state of a session:

const status = await verifier.getVerificationStatus(session.sessionId)
console.log(status.state)   // 'created' | 'qr_displayed' | 'opened' | ... | 'verified'
console.log(status.result)  // VerificationResult — populated when state is terminal

API reference

new CredenceVerifier(config)

| Parameter | Type | Description | |---|---|---| | config.baseUrl | string | Base URL of your Credence ID Online Verifier instance |


activate(config): Promise<void>

Authenticates the SDK with the Credence ID server. Must be called before any other method.

| Parameter | Type | Required | Description | |---|---|---|---| | licenseKey | string | Yes | License key issued by CredenceID (starts with CS-) | | profileId | string | Yes | UUID of the reader profile | | webhookUrl | string | No | HTTPS URL to receive webhook POSTs on session completion |

Throws ActivationError (with .code) on invalid credentials.


createVerificationSession(opts): Promise<VerificationSession>

Creates a new verification session and returns the QR code.

| Parameter | Type | Required | Description | |---|---|---|---| | purpose | string | Yes | Business intent (e.g. 'age_check', 'identity_check') | | referenceId | string | No | Your internal transaction reference for audit |

Returns:

{
  sessionId: string       // UUID v4
  qrUrl: string           // URL encoded in the QR code
  qrImageBase64: string   // Base64 PNG data URI — use as <img src="...">
  expiresAt: Date         // When the session expires
}

Throws SessionError (with .code) on API errors. Throws Error if activate() has not been called.


renderQRCode(qrImageBase64, container): { remove: () => void }

Injects a QR code <img> into a DOM container. Browser-only (no-op in Node.js).

| Parameter | Type | Description | |---|---|---| | qrImageBase64 | string | Base64 data URI from createVerificationSession() | | container | string \| HTMLElement | CSS selector string or HTMLElement reference |

Returns { remove() } — call remove() to cleanly delete the injected image.


subscribeToVerificationResult(sessionId, callback): Promise<() => void>

Listens for the session result and fires callback when the session reaches a terminal state.

| Parameter | Type | Description | |---|---|---| | sessionId | string | Session ID from createVerificationSession() | | callback | (result: VerificationResult) => void | Called once when the result arrives |

Returns a Promise that resolves to an unsubscribe function — await the call before invoking the unsubscribe function.

Transport is selected automatically:

| Environment | Transport | Notes | |---|---|---| | Browser (window defined) | SSE (EventSource) | Low-latency push; preferred for POS web UIs | | Node.js (window undefined) | Polling every 2 s | Fallback; use webhook instead when possible |

See Server-side integration patterns for guidance on which mode to use.


cancelVerificationSession(sessionId): Promise<void>

Cancels an active session. Throws SessionError if the session is not found or already in a terminal state.


getVerificationStatus(sessionId): Promise<SessionStatusResponse>

Fetches the current state of a session.

Types

type SessionStatus =
  | 'created' | 'qr_displayed' | 'opened' | 'in_progress' | 'fallback_started'
  | 'verified' | 'denied' | 'failed' | 'expired' | 'cancelled'

interface VerificationResult {
  sessionId: string
  status: SessionStatus
  purpose: string
  decision?: string    // 'verified' when status is 'verified'
  verifiedAt?: number  // Unix timestamp (ms)
}

interface SessionStatusResponse {
  sessionId: string
  state: SessionStatus
  purpose: string
  referenceId?: string
  qrUrl: string
  qrImageBase64: string
  expiresAt: Date
  result?: VerificationResult
}

class ActivationError extends Error {
  code: string  // e.g. 'INVALID_LICENSE_KEY', 'EXPIRED_LICENSE'
}

class SessionError extends Error {
  code: string  // e.g. 'SESSION_NOT_FOUND', 'UNSUPPORTED_PURPOSE', 'SESSION_ALREADY_TERMINAL'
}

Error handling

import { ActivationError, SessionError } from '@credenceid/verifier-sdk'

try {
  await verifier.activate({ licenseKey: 'bad', profileId: 'x' })
} catch (e) {
  if (e instanceof ActivationError) {
    console.error(e.code, e.message)  // 'INVALID_LICENSE_KEY', 'License key not found'
  }
}

try {
  await verifier.cancelVerificationSession('nonexistent-id')
} catch (e) {
  if (e instanceof SessionError) {
    console.error(e.code)  // 'SESSION_NOT_FOUND'
  }
}

Token lifecycle

The SDK manages access tokens automatically — callers never need to handle token expiry.

| Behaviour | How it works | |---|---| | Proactive pre-expiry refresh | Before each API call the SDK checks whether the token expires within the next 30 seconds. If so, it re-calls activate() with the stored credentials before making the request. | | Transparent 401 recovery | If an API call unexpectedly returns 401 (e.g. the server restarted and invalidated tokens), the SDK re-activates once and retries the request. The caller sees a successful response. | | Concurrent refresh deduplication | If multiple API calls are in-flight simultaneously when the token needs refreshing, only one activate() HTTP request is sent. All concurrent callers wait on the same promise and receive the new token together. |

If re-activation itself fails (e.g. the license key has been revoked), an ActivationError is thrown and propagates to the caller.

import { ActivationError } from '@credenceid/verifier-sdk'

try {
  await verifier.createVerificationSession({ purpose: 'age_check' })
} catch (e) {
  if (e instanceof ActivationError) {
    // Token could not be refreshed — credentials may be invalid or revoked
    console.error('Re-activation failed:', e.code, e.message)
  }
}

Local development

# Build
npm run build

# Watch mode
npm run dev

# Tests
npm test

To test against a local Online Verifier instance:

const verifier = new CredenceVerifier({ baseUrl: 'http://localhost:8080' })