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

dhanavega-sdk

v0.1.0

Published

Official TypeScript client for the Dhanavega API — generated types (openapi-typescript) over a thin openapi-fetch runtime core (auth, Idempotency-Key, problem+json, pagination). See issue #41, ADR 0037.

Readme

dhanavega-sdk

Official TypeScript client for the Dhanavega API. Generated types (openapi-typescript) over a thin openapi-fetch runtime core — bearer auth, Idempotency-Key autogeneration, RFC 9457 problem+json error parsing, If-Match concurrency, and cursor pagination. See issue #41 and ADR 0037 for the design rationale.

Status: buildable and test-covered; not yet published to npm (issue #41 — publication is a manual step performed by the maintainers once the platform reaches its India-GA milestone). Everything below documents the eventual npm install dhanavega-sdk experience.

Install

pnpm add dhanavega-sdk

Quickstart

import { createDhanavegaClient } from 'dhanavega-sdk';

const client = createDhanavegaClient({
  baseUrl: 'https://api.dhanavega.example',
  auth: { token: '…' }, // or auth: { getToken: () => fetchShortLivedToken() }
});

const { data } = await client.los.GET('/los/leads');

Each module surface is its own typed openapi-fetch client: client.admin, client.brn, client.chn, client.cus, client.lcs, client.lms, client.los, client.xc, client.partner. All share the same middleware stack. Types for a module are also importable standalone via subpath exports, e.g.:

import type { components } from 'dhanavega-sdk/los';
type Application = components['schemas']['Application'];

Webhook payload shapes (types only — no runtime client) are available from dhanavega-sdk/webhooks/inbound-provider and dhanavega-sdk/webhooks/outbound-partner.

Auth

tenant_id is never sent by the client — the API derives it server-side from the bearer JWT (api-docs/02-auth-tenancy-scopes.md). Supply either a static token or a getToken callback (invoked fresh on every request, so you can refresh a short-lived token):

createDhanavegaClient({ baseUrl, auth: { getToken: async () => await refreshToken() } });

Idempotency

Every POST/PUT/PATCH/DELETE operation's contract requires an Idempotency-Key header parameter (api-docs/04-idempotency-concurrency-webhooks.md §1) — openapi-typescript therefore types it as a required params.header field on every mutating call. Use withIdempotencyKey() to satisfy that type and generate the value in one step:

import { withIdempotencyKey } from 'dhanavega-sdk';

await client.los.POST('/los/applications', {
  params: { header: withIdempotencyKey() },
  body: { borrower_id, product_id, product_version_id, channel: 'SELF_SERVE', currency_code: 'INR' },
});

Pass your own key to deliberately replay an attempt: withIdempotencyKey('my-own-key'). A stored replay comes back with the Idempotency-Replayed: true header, surfaced on a thrown DhanavegaProblem as .idempotencyReplayed. (A runtime safety-net middleware also fills the header in automatically at the Request level if it's ever missing — belt and suspenders, not the primary calling convention.)

Error handling

Every non-2xx response throws a DhanavegaProblem — never a bare non-2xx Response — parsed from the platform's RFC 9457 application/problem+json envelope (api-docs/03-errors-pagination.md §1). Branch on .code (a closed DhanavegaErrorCode union), never on .message/detail text:

import { DhanavegaProblem } from 'dhanavega-sdk';

try {
  await client.los.POST('/los/applications', { params: { header: withIdempotencyKey() }, body });
} catch (err) {
  if (err instanceof DhanavegaProblem) {
    if (err.code === 'VALIDATION_FAILED') {
      for (const fieldError of err.errors ?? []) console.log(fieldError.pointer, fieldError.rule);
    } else if (err.code === 'RATE_LIMITED') {
      console.log('retry after', err.retryAfter);
    }
  }
}

Concurrency (If-Match)

import { withIfMatch } from 'dhanavega-sdk';

await client.los.PATCH('/los/applications/{id}', {
  params: { path: { id: applicationId } },
  body: patch,
  ...withIfMatch(etag),
});

Missing If-Match on a mutable-entity mutation → 428 PRECONDITION_REQUIRED; a stale one → 412 VERSION_CONFLICT.

Pagination

import { paginate } from 'dhanavega-sdk';

for await (const lead of paginate((cursor) =>
  client.los
    .GET('/los/leads', { params: { query: { 'page[after]': cursor } } })
    .then(({ data }) => data!),
)) {
  console.log(lead);
}

paginate walks page.has_more / page.next_cursor until the stream ends — cursors are opaque; never parse or construct them yourself.

Regenerating types

pnpm --filter dhanavega-sdk generate

Regenerates every committed file under src/generated/ from planning/api-docs/openapi/**. Run this whenever a contract YAML changes — test/drift.spec.ts fails CI if the committed types fall out of sync.

Publish procedure (manual, first release)

Publication is intentionally not automated yet (issue #41). CI's sdk-release.yml carries a publish-sdk-npm job gated behind the PUBLISH_ENABLED repo variable, which is unset today. To publish manually once the maintainers decide to:

pnpm --filter dhanavega-sdk build
pnpm --filter dhanavega-sdk publish --access public --no-git-checks

(or from the repo root: pnpm sdk:publish:npm).

Development

pnpm --filter dhanavega-sdk generate   # regenerate src/generated/*.ts
pnpm --filter dhanavega-sdk typecheck
pnpm --filter dhanavega-sdk test
pnpm --filter dhanavega-sdk build