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

kcv-sdk

v1.0.3

Published

TypeScript/JavaScript SDK for the KCV (Khmer Computer Vision) REST API — OCR extraction, passive face liveness, and face comparison.

Readme

kcv-sdk

A production-ready, lightweight TypeScript/JavaScript SDK for the KCV (Khmer Computer Vision) REST API. It provides strongly typed models, a fluent client, pluggable authentication, automatic retries, and a rich error hierarchy — with zero runtime dependencies (built on the native fetch), shipping both ESM and CommonJS with full type declarations.

The current API surface covers OCR document extraction (POST /ocr/extract), passive face liveness (POST /face/liveness/passive), and face comparison (POST /face/compare). The SDK is architected so additional endpoints can be added without touching the transport layer.

This is the TypeScript port of the Java SDK (java-kcv-sdk) and mirrors its feature set.


Table of Contents

  1. Features
  2. Requirements
  3. Installation
  4. Quick Start
  5. Configuration
  6. Auto-Configuration (Environment)
  7. Endpoints & Usage Examples
  8. Response Models
  9. Error Handling
  10. Retry & Resilience
  11. Logging
  12. Proxy & TLS
  13. Best Practices
  14. Assumptions
  15. Versioning
  16. Publishing
  17. Changelog
  18. License

Features

  • ✅ Fluent client — options object (new KcvClient({ ... })) or builder (KcvClient.builder()...build())
  • Auto-configuration from the environmentkcv() / createClientFromEnv() read KCV_* vars, zero wiring
  • ✅ Strongly typed request/response models (fully nested) for every endpoint
  • ESM + CommonJS dual package with bundled .d.ts type declarations
  • Zero runtime dependencies — built on the native fetch (Node 18+)
  • ✅ Pluggable authentication: API key (x-api-key), bearer, basic, custom header
  • ✅ Automatic JSON (de)serialization with camelCase normalization of responses
  • ✅ Configurable retry with exponential backoff (429/502/503/504 + network timeouts), honoring Retry-After
  • ✅ Typed error hierarchy mapped from HTTP status codes
  • ✅ Pluggable logging (never logs credentials or image payloads)
  • ✅ Transparent gzip, request timeouts, and optional proxy / TLS control (via undici)

Requirements

| Requirement | Version | | ----------- | ---------------------------- | | Node.js | ≥ 18 (native fetch) | | TypeScript | ≥ 5 (optional; JS works too) |

For older runtimes without a global fetch, pass your own via the fetch option.

Installation

npm install kcv-sdk
# or: pnpm add kcv-sdk / yarn add kcv-sdk

Quick Start

ESM / TypeScript

import { KcvClient } from 'kcv-sdk';
import { readFile } from 'node:fs/promises';

const client = new KcvClient({
  baseUrl: 'https://<kcv-api-gateway>/kcv',
  apiKey: 'kcv_sk_uat_xxx',
  timeoutMs: 30_000,
  retryCount: 3,
});

const image = (await readFile('id.jpg')).toString('base64');

const result = await client.ocr.extract({ image, crop: false });
console.log('ID number:', result.physical?.idNumber);
console.log('Name (EN):', result.physical?.fullNameEn);
console.log('MRZ valid:', result.mrz?.valid);

CommonJS

const { KcvClient } = require('kcv-sdk');

const client = new KcvClient({ apiKey: 'kcv_sk_uat_xxx' });
const result = await client.ocr.extract({ image });

Builder (parity with the Java SDK)

const client = KcvClient.builder()
  .baseUrl('https://<kcv-api-gateway>/kcv')
  .apiKey('kcv_sk_uat_xxx')
  .timeout(30_000)
  .retryCount(3)
  .build();

Zero-config (from environment)

import { kcv } from 'kcv-sdk';

// Reads KCV_API_KEY / KCV_BASE_URL / … from process.env on first use, then caches the client.
const result = await kcv().ocr.extract({ image });

See Auto-Configuration (Environment) for all recognized variables.

Reuse a single client instance across requests. If you enable a proxy or disable TLS verification, call await client.close() on shutdown to release the underlying dispatcher.

Configuration

All options (everything is optional):

| Option | Type | Default | Description | | ------------------------ | ------------------------ | -------------- | ------------------------------------------------------- | | baseUrl | string | UAT gateway | API base URL (trailing slash trimmed) | | apiKey | string | — | API key sent as x-api-key | | apiKeyHeader | string | x-api-key | Custom API-key header name | | bearerToken | string | — | Authorization: Bearer <token> | | basicAuth | { username, password } | — | HTTP Basic auth | | authenticationProvider | AuthenticationProvider | — | Fully custom auth strategy (wins over the above) | | timeoutMs | number | 30000 | Per-request timeout in ms (0 disables) | | retryCount | number | 2 | Automatic retries for transient failures | | retryBaseDelayMs | number | 500 | Initial exponential-backoff delay | | retryMaxDelayMs | number | 10000 | Cap for a single backoff step | | headers | Record<string,string> | — | Extra headers on every request | | sslVerification | boolean | true | Disable only for trusted test envs (needs undici) | | proxyUrl | string | — | HTTP(S) proxy (needs undici) | | dispatcher | unknown | — | Advanced: an undici Dispatcher passed to fetch | | fetch | FetchLike | global fetch | Override the fetch implementation | | logger | Logger | no-op | Debug logging sink |

Authentication

The SDK auto-detects the API-key method (x-api-key) and injects it on every request. Other schemes are supported (precedence: authenticationProviderapiKeybearerTokenbasicAuth):

new KcvClient({ apiKey: 'kcv_sk_uat_xxx' }); // x-api-key
new KcvClient({ apiKey: 'kcv_sk_uat_xxx', apiKeyHeader: 'x-api-key' });
new KcvClient({ bearerToken: 'eyJhbGci...' }); // Authorization: Bearer
new KcvClient({ basicAuth: { username: 'u', password: 'p' } }); // Authorization: Basic
new KcvClient({ authenticationProvider: { apply: (h) => (h['X-Sig'] = sign()) } });

Credentials are never logged.

Auto-Configuration (Environment)

Prefer zero manual wiring? Configure the client entirely from environment variables — the JS analog of the Java SDK's Spring Boot auto-configuration (which binds kcv.* from application.yml).

import { kcv } from 'kcv-sdk';

// Auto-configured from process.env on first use, then cached process-wide:
const result = await kcv().ocr.extract({ image });
# .env / deployment environment
KCV_API_KEY=kcv_sk_uat_xxx
KCV_BASE_URL=https://<kcv-api-gateway>/kcv
KCV_TIMEOUT_MS=30000
KCV_RETRY_COUNT=3

For an explicit instance, use createClientFromEnv() — optionally merging overrides on top of the environment (overrides win) — or optionsFromEnv() to get just the resolved options:

import { createClientFromEnv, optionsFromEnv } from 'kcv-sdk';

const client = createClientFromEnv(); // pure environment
const client2 = createClientFromEnv({ retryCount: 5 }); // env + overrides
const opts = optionsFromEnv(); // resolved options object

Recognized variables

| Variable | Maps to | Notes | | ------------------------------------------- | ------------------ | --------------------------------------- | | KCV_BASE_URL | baseUrl | | | KCV_API_KEY | apiKey | sent as x-api-key | | KCV_API_KEY_HEADER | apiKeyHeader | default x-api-key | | KCV_BEARER_TOKEN | bearerToken | | | KCV_BASIC_USERNAME / KCV_BASIC_PASSWORD | basicAuth | | | KCV_TIMEOUT_MS | timeoutMs | integer ms | | KCV_RETRY_COUNT | retryCount | integer | | KCV_RETRY_BASE_DELAY_MS | retryBaseDelayMs | integer ms | | KCV_RETRY_MAX_DELAY_MS | retryMaxDelayMs | integer ms | | KCV_SSL_VERIFICATION | sslVerification | true/false/1/0/yes/no | | KCV_PROXY_URL | proxyUrl | needs the optional undici package | | KCV_HEADERS | headers | JSON object, e.g. {"x-tenant":"acme"} | | KCV_DEBUG | logger | true wires a console logger |

Authentication precedence matches the client (apiKeybearerTokenbasicAuth). Malformed numeric/boolean/JSON values throw a KcvError at construction so misconfiguration surfaces early. In tests, call resetDefaultClient() to force kcv() to re-read the environment.

Endpoints & Usage Examples

Runnable examples live under examples/: ocr-extract.ts and face-verification.ts.

POST /ocr/extract — OCR document extraction

const res = await client.ocr.extract({
  image: base64Image, // required
  crop: false, // optional, defaults to false
});

| Field | Type | Required | Description | | ------- | --------- | -------- | -------------------------------------- | | image | string | yes | Base64-encoded document image | | crop | boolean | no | Auto-crop before OCR (default false) |

POST /face/liveness/passive — passive liveness detection

const res = await client.face.passiveLiveness({ image: base64Image });
if (res.isLive) {
  // proceed
} else {
  console.log('Spoof suspected:', res.status, 'pFake=', res.scores?.pFake);
}

| Field | Type | Required | Description | | ------- | -------- | -------- | ------------------------- | | image | string | yes | Base64-encoded face image |

POST /face/compare — face comparison

const res = await client.face.compare({
  sourceImage: selfieBase64, // required
  targetImage: idPortraitBase64, // required
});
const similarity = res.faceMatches?.[0]?.similarity ?? 0; // 0–100

| Field | Type | Required | Description | | ------------- | -------- | -------- | -------------------------------- | | sourceImage | string | yes | Base64-encoded source face image | | targetImage | string | yes | Base64-encoded target face image |

Response Models

Response keys are normalized to camelCase (e.g. document_typedocumentType, Similaritysimilarity). Dates are ISO-8601 strings (yyyy-MM-dd).

OcrExtractResponse
├── correlationId, requestId, documentType, countryCode
├── physical: Physical (idNumber, fullNameKh/En, sex, nationality, dateOfBirth,
│              placeOfBirth, currentAddress, issueDate, expiryDate, physicalAttributes)
├── mrz: Mrz (rawLine1..3, documentNumber, valid, nameMatchesPrinted, ...)
├── raw: Raw (fullText, engineVersion)
└── lines: string[]

LivenessResponse
├── isLive, result, status
├── scores: LivenessScores (pReal, pFake)
├── gate, verdictStrict, verdictAny
├── models: LivenessModel[] (name, available, pReal, threshold, real)
├── faceDetected, faceBox: number[], facesFound, threshold, latencyMs

FaceCompareResponse
├── faceMatches: FaceMatch[] (similarity: number  // 0–100)
└── latencyMs

All model interfaces are exported for use in your own types.

Error Handling

Every SDK error extends KcvError. HTTP errors map to specific subclasses of KcvApiError:

| HTTP status | Error | | ----------------- | ---------------------------------------------- | | 400 | ValidationError | | 401 | AuthenticationError | | 403 | ForbiddenError | | 404 | ResourceNotFoundError | | 409 | ConflictError | | 429 | RateLimitError (exposes retryAfterSeconds) | | 5xx | ServerError | | other ≥ 400 | KcvApiError | | network / timeout | NetworkError |

Every KcvApiError exposes statusCode, errorBody, rawBody, correlationId, and requestId.

import {
  KcvError,
  ValidationError,
  AuthenticationError,
  RateLimitError,
  NetworkError,
} from 'kcv-sdk';

try {
  await client.ocr.extract({ image });
} catch (err) {
  if (err instanceof ValidationError) console.warn('Bad request:', err.errorBody);
  else if (err instanceof AuthenticationError) console.error('Bad API key');
  else if (err instanceof RateLimitError) console.warn('Retry after', err.retryAfterSeconds, 's');
  else if (err instanceof NetworkError) console.error('Cannot reach KCV:', err.message);
  else if (err instanceof KcvError) throw err; // any other SDK error
}

Retry & Resilience

The SDK automatically retries only transient failures:

  • HTTP 429, 502, 503, 504
  • Network errors and timeouts

Backoff is exponential (retryBaseDelayMs × 2^(attempt-1), capped at retryMaxDelayMs). A Retry-After header on a 429 is honored (capped by retryMaxDelayMs). Non-retryable statuses (e.g. 400, 401, 404) fail fast. Set retryCount: 0 to disable retries.

Logging

Pass a logger to receive debug output (request method/URL, response status, timing, and gateway correlationId/requestId). Credentials and image payloads are never logged.

import { KcvClient, consoleLogger } from 'kcv-sdk';

const client = new KcvClient({ apiKey: 'kcv_sk_uat_xxx', logger: consoleLogger() });

Provide any object implementing the Logger interface ({ debug, info, warn, error }) to route logs into your own framework. The default is a no-op.

Proxy & TLS

Native fetch has no built-in proxy support, so proxy and TLS-verification control use undici (an optional peer dependency):

npm install undici
// via convenience options (the SDK builds an undici dispatcher lazily)
const client = new KcvClient({ apiKey: 'kcv_sk_uat_xxx', proxyUrl: 'http://proxy.internal:8080' });

// or pass your own dispatcher for full control
import { ProxyAgent } from 'undici';
const client2 = new KcvClient({
  apiKey: 'kcv_sk_uat_xxx',
  dispatcher: new ProxyAgent('http://proxy.internal:8080'),
});

await client.close(); // releases a dispatcher the SDK created

⚠️ sslVerification: false disables TLS certificate checks and is for trusted test gateways only — never in production.

Best Practices

  • Reuse one client across requests; construct it once at startup.
  • Close on shutdown (await client.close()) when using a proxy / custom dispatcher.
  • Keep TLS verification on in production.
  • Store keys securely (env vars / secret manager), never in source control.
  • Narrow errors with instanceof; fall back to KcvError.
  • Tune timeoutMs and retryCount to your latency/SLA needs.

Assumptions

The KCV API documents each endpoint's success response but leaves some details unspecified. Where ambiguous, the SDK makes documented, conservative choices:

  1. Base URL split. .../kcv/<path> is split into base path .../kcv and the endpoint path. Override baseUrl for production.
  2. Error schema. Not formally defined; ApiErrorBody maps common gateway fields and tolerates unknown ones; the raw body is always available via error.rawBody.
  3. Status-code mapping. Standard REST conventions (400 → validation, 401 → auth, …).
  4. Dates are kept as ISO-8601 strings (yyyy-MM-dd) to avoid timezone ambiguity.
  5. Retryable statuses: 429/502/503/504 and network timeouts.
  6. faceBox order is exposed as a raw number[]; the API does not label its four values.
  7. Similarity casing: the capitalized "Similarity" key is normalized to FaceMatch.similarity (a number, 0–100).

Versioning

This project follows Semantic Versioning. The current version is 1.0.0. Breaking changes bump the major version; new backward-compatible endpoints/fields bump the minor version.

Publishing

Released to npm as kcv-sdk. See PUBLISHING.md for the full release process (npm publish, provenance, and a GitHub Actions example).

Changelog

See CHANGELOG.md.

License

Apache License 2.0 © Khmer Computer Vision (KCV).