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

@dealer-finance/sdk

v0.0.1

Published

TypeScript SDK for Dealer Finance Group API

Readme

@dealer-finance/sdk

TypeScript SDK for Dealer Finance Group API - A production-ready, type-safe client library for JavaScript/TypeScript applications.

Features

  • 🎯 TypeScript-First: Full type safety with excellent IntelliSense support
  • 🔄 Automatic Token Refresh: Seamless authentication handling with auto-retry on token expiration
  • 🔁 Smart Retry Logic: Exponential backoff with jitter for failed requests
  • 📦 Tree-Shakeable: Optimized bundle size with code splitting
  • 🌐 Universal: Works in Browser, Node.js, and SSR environments
  • 🔌 Extensible: Plugin system for custom behavior and logging
  • 📊 Progress Tracking: Built-in upload progress for file operations
  • Modern: Built with latest TypeScript (ES2022+) and Vitest
  • Battle-Tested: 56 passing E2E tests against production API

Installation

npm install @dealer-finance/sdk axios
# or
yarn add @dealer-finance/sdk axios
# or
pnpm add @dealer-finance/sdk axios

Note: axios is a peer dependency and must be installed separately.

Quick Start

import { DealerFinanceSDK } from '@dealer-finance/sdk';

// Initialize the SDK
const sdk = new DealerFinanceSDK({
  baseURL: 'https://api.dealer.techlabx.dev/v1',
});

// Login
const response = await sdk.auth.login({
  email: '[email protected]',
  password: 'Demo123!',
});

console.log('Access Token:', response.accessToken);
console.log('User:', response.user);

// Get user profile
const profile = await sdk.users.getProfile();
console.log('Profile:', profile);

// List loans with pagination
const loans = await sdk.loans.list({ limit: 10 });
console.log('Loans:', loans.data);
console.log('Pagination:', loans.meta);

// Iterate through all loans automatically
for await (const loan of sdk.loans.listAll({ status: 'ACTIVE' })) {
  console.log('Loan:', loan);
}

// Logout
await sdk.auth.logout();

Configuration

Basic Configuration

const sdk = new DealerFinanceSDK({
  baseURL: 'https://api.dealer.techlabx.dev/v1',
  timeout: 30000, // 30 seconds
  debug: false,
  tokenStorage: 'memory', // or 'localStorage', 'sessionStorage'
});

Fluent Configuration API

const sdk = new DealerFinanceSDK({ baseURL: 'https://api.dealer.techlabx.dev/v1' })
  .withTimeout(30000)
  .withDebug(true)
  .withTokenStorage('localStorage')
  .withRetry({
    maxRetries: 3,
    baseDelay: 1000,
    backoff: 'exponential',
  })
  .onTokenExpired(() => {
    console.log('Token expired, redirecting to login...');
    window.location.href = '/login';
  });

Configuration Options

interface SDKConfig {
  // Required
  baseURL: string; // API base URL

  // Optional
  timeout?: number; // Request timeout in ms (default: 30000)
  tokenStorage?: 'localStorage' | 'sessionStorage' | 'memory' | 'cookie';
  retry?: {
    maxRetries: number; // Default: 3
    backoff: 'exponential' | 'linear' | 'constant'; // Default: 'exponential'
    baseDelay: number; // Default: 1000ms
    maxDelay: number; // Default: 30000ms
    jitter: boolean; // Default: true
    retryableStatusCodes: number[]; // Default: [408, 429, 500, 502, 503, 504]
  };
  debug?: boolean; // Enable debug logging (default: false)
  headers?: Record<string, string>; // Custom headers

  // Lifecycle Hooks
  onTokenExpired?: () => void | Promise<void>;
  onUnauthorized?: (error: AuthError) => void | Promise<void>;
  onRequest?: (config: AxiosRequestConfig) => void | Promise<void>;
  onResponse?: (response: any) => void | Promise<void>;
  onError?: (error: SDKError) => void | Promise<void>;
}

API Resources

Authentication (sdk.auth)

// Login
const response = await sdk.auth.login({
  email: '[email protected]',
  password: 'Demo123!',
});

// Register
const response = await sdk.auth.register({
  email: '[email protected]',
  password: 'Demo123!',
  firstName: 'John',
  lastName: 'Doe',
  role: 'CLIENT', // Optional: 'ADMIN', 'BROKER', 'CLIENT'
});

// Logout
await sdk.auth.logout();

// Refresh token
const tokens = await sdk.auth.refreshToken();

// Password reset flow
await sdk.auth.requestPasswordReset({ email: '[email protected]' });
await sdk.auth.resetPassword({ 
  token: 'reset-token',
  newPassword: 'NewDemo123!' 
});

// Email verification
await sdk.auth.verifyEmail({ token: 'verification-token' });
await sdk.auth.resendVerificationEmail();

Users (sdk.users)

// Get current user profile
const profile = await sdk.users.getProfile();

// Update profile
const updated = await sdk.users.updateProfile({
  firstName: 'John',
  lastName: 'Doe',
  phoneNumber: '+61412345678',
});

// List users (admin only)
const users = await sdk.users.list({
  page: 1,
  limit: 10,
  search: 'john',
  role: 'BROKER',
  status: 'ACTIVE',
});

// Iterate all users (admin only)
for await (const user of sdk.users.listAll({ role: 'BROKER' })) {
  console.log(user);
}

// Get user by ID (admin only)
const user = await sdk.users.get('user-id');

// Update user (admin only)
const updated = await sdk.users.updateUser('user-id', {
  status: 'INACTIVE',
});

// Delete user (admin only)
await sdk.users.remove('user-id');

Loans (sdk.loans)

// Create loan
const loan = await sdk.loans.create({
  loanAmount: 50000,
  loanTerm: 60,
  interestRate: 5.5,
  purpose: 'CAR_PURCHASE',
  // ... other fields
});

// Get loan by ID
const loan = await sdk.loans.get('loan-id');

// List loans
const loans = await sdk.loans.list({
  page: 1,
  limit: 10,
  status: 'ACTIVE',
  partnerId: 'partner-id',
});

// Iterate all loans
for await (const loan of sdk.loans.listAll({ status: 'ACTIVE' })) {
  console.log(loan);
}

// Update loan
const updated = await sdk.loans.update('loan-id', {
  status: 'APPROVED',
  notes: 'Approved by broker',
});

// Assign broker to loan
const assigned = await sdk.loans.assignBroker('loan-id', 'broker-id');

// Delete loan
await sdk.loans.remove('loan-id');

Partners (sdk.partners)

// Create partner
const partner = await sdk.partners.create({
  firstName: 'Jane',
  lastName: 'Smith',
  email: '[email protected]',
  phoneNumber: '+61498765432',
  // ... other fields
});

// Get partner by ID
const partner = await sdk.partners.get('partner-id');

// List partners
const partners = await sdk.partners.list({
  page: 1,
  limit: 10,
  search: 'smith',
});

// Iterate all partners
for await (const partner of sdk.partners.listAll()) {
  console.log(partner);
}

// Update partner
const updated = await sdk.partners.update('partner-id', {
  phoneNumber: '+61412345678',
});

// Delete partner
await sdk.partners.remove('partner-id');

Files (sdk.files)

// Upload file with progress tracking
const file = new File(['content'], 'document.pdf', { type: 'application/pdf' });

const uploaded = await sdk.files.upload(file, {
  onUploadProgress: (progress) => {
    console.log(`Upload progress: ${progress.percentage}%`);
    console.log(`Uploaded: ${progress.loaded} / ${progress.total} bytes`);
  },
});

console.log('File ID:', uploaded.id);
console.log('File URL:', uploaded.url);

// Download file
const blob = await sdk.files.download('file-id');

// Delete file
await sdk.files.remove('file-id');

Pagination

The SDK supports two types of pagination:

Cursor-Based Pagination (Default)

const response = await sdk.loans.list({ limit: 10 });

console.log(response.data); // Array of loans
console.log(response.meta.hasNextPage); // boolean
console.log(response.meta.nextCursor); // string | null
console.log(response.meta.hasPreviousPage); // boolean
console.log(response.meta.previousCursor); // string | null

Offset-Based Pagination

const response = await sdk.loans.list({ page: 2, limit: 10 });

console.log(response.data); // Array of loans
console.log(response.meta.page); // 2
console.log(response.meta.limit); // 10
console.log(response.meta.total); // Total count (if available)

Auto-Pagination

// Automatically fetches all pages
for await (const loan of sdk.loans.listAll({ status: 'ACTIVE' })) {
  console.log(loan);
  // Process each loan individually
}

Error Handling

import {
  AuthError,
  ValidationError,
  NetworkError,
  NotFoundError,
  ServerError,
} from '@dealer-finance/sdk';

try {
  await sdk.auth.login(credentials);
} catch (error) {
  if (error instanceof AuthError) {
    // 401 Unauthorized
    console.error('Authentication failed:', error.message);
  } else if (error instanceof ValidationError) {
    // 400 Bad Request
    console.error('Validation failed:', error.details);
  } else if (error instanceof NotFoundError) {
    // 404 Not Found
    console.error('Resource not found:', error.message);
  } else if (error instanceof NetworkError) {
    // Network/Connection errors
    console.error('Network error:', error.message);
  } else if (error instanceof ServerError) {
    // 500 Internal Server Error
    console.error('Server error:', error.message);
  }
}

Error Properties

error.message; // Error message
error.statusCode; // HTTP status code
error.traceId; // Request trace ID for debugging
error.timestamp; // Error timestamp
error.isRetryable; // Whether the error can be retried

Plugins

Logger Plugin

import { DealerFinanceSDK, LoggerPlugin } from '@dealer-finance/sdk';

const sdk = new DealerFinanceSDK({
  baseURL: 'https://api.dealer.techlabx.dev/v1',
}).use(new LoggerPlugin(true)); // Enable debug logging

// Logs all requests and responses
await sdk.auth.login({ email: '[email protected]', password: 'Demo123!' });
// [2025-11-18T14:00:00.000Z] → Request: POST /auth/login
// [2025-11-18T14:00:00.362Z] ← Response: 200 POST /auth/login

Custom Plugin

import type { Plugin } from '@dealer-finance/sdk';

class CustomPlugin implements Plugin {
  name = 'custom';
  version = '1.0.0';

  onRequest(config) {
    console.log('Before request:', config.url);
    return config;
  }

  onResponse(response) {
    console.log('After response:', response.status);
    return response;
  }

  onError(error) {
    console.error('Request error:', error.message);
    return error;
  }
}

sdk.use(new CustomPlugin());

Advanced Usage

Abort Requests

const controller = new AbortController();

// Pass signal to request
const promise = sdk.loans.list({ limit: 10 }, controller.signal);

// Cancel request
controller.abort();

try {
  await promise;
} catch (error) {
  console.log('Request cancelled');
}

Token Management

// Get token storage
const storage = sdk.getAxiosInstance().defaults.headers.common;

// Manual token refresh
await sdk.auth.refreshToken();

// Clear tokens
await sdk.destroy();

TypeScript Support

Full TypeScript support with type definitions for all APIs:

import type {
  User,
  Loan,
  Partner,
  UserRole,
  LoanStatus,
  PaginatedResponse,
} from '@dealer-finance/sdk';

// All types are exported and available
const user: User = await sdk.users.getProfile();
const loans: PaginatedResponse<Loan> = await sdk.loans.list();

Development

# Install dependencies
pnpm install

# Run unit tests
pnpm test:unit

# Run E2E tests (requires production API)
pnpm test:e2e

# Run all tests with coverage
pnpm test:coverage

# Build for production
pnpm build

# Watch mode for development
pnpm dev

# Type checking
pnpm typecheck

Testing

The SDK includes comprehensive E2E tests against production API:

  • ✅ 18 Authentication tests (login, register, logout, password reset)
  • ✅ 15 User management tests (profile, CRUD operations, pagination)
  • ✅ 12 Multi-role tests (admin, broker, client permissions)
  • ✅ 16 SDK features tests (plugins, config, lifecycle hooks)

Run tests:

# Run E2E tests
E2E_API_URL=https://api.dealer.techlabx.dev/v1 pnpm test:e2e

# Run with debug mode
E2E_DEBUG=true pnpm test:e2e

Browser Support

  • Chrome/Edge (latest)
  • Firefox (latest)
  • Safari (latest)
  • Node.js 18+

License

MIT © Dealer Finance Group

Support

For issues and feature requests, please open an issue on GitHub.

Changelog

0.0.1 (2025-11-18)

  • 🎉 Initial beta release
  • ✅ Full TypeScript support
  • 🔐 Authentication & authorization
  • 📦 User, Loan, Partner, File management
  • 📄 Pagination (cursor & offset-based)
  • 🔄 Auto-retry with exponential backoff
  • 🔌 Plugin system
  • ✅ Comprehensive E2E tests (56 passing)