@dealer-finance/sdk
v0.0.1
Published
TypeScript SDK for Dealer Finance Group API
Maintainers
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 axiosNote:
axiosis 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 | nullOffset-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 retriedPlugins
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/loginCustom 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 typecheckTesting
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:e2eBrowser 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)
