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

@osise/api-client

v0.0.5

Published

Official TypeScript SDK for the Osise API - connecting consumers with skilled artisans

Downloads

257

Readme

@osise/api-client

Official TypeScript SDK for the Osise API - connecting consumers with skilled artisans in Nigeria.

Installation

npm install @osise/api-client
# or
yarn add @osise/api-client
# or
pnpm add @osise/api-client

Quick Start

Basic Usage

import { OsiseClient, BrowserTokenStorage } from '@osise/api-client';

// Create client instance
const client = new OsiseClient({
  baseUrl: 'https://api.osise.com',
  storage: new BrowserTokenStorage(), // Persists tokens in localStorage
  onAuthRequired: () => {
    // Handle auth required (e.g., redirect to login)
    window.location.href = '/login';
  },
});

// Request OTP
const otpResponse = await client.auth.requestOtp({
  phoneNumber: '+2348012345678',
  purpose: 'Login',
});

// Verify OTP
const authResponse = await client.auth.verifyOtp({
  phoneNumber: '+2348012345678',
  code: '123456',
  deviceId: 'unique-device-id',
  deviceName: 'iPhone 15',
  deviceType: 'iOS',
});

// Tokens are automatically stored and used for subsequent requests
console.log('Logged in as:', authResponse.data?.user.firstName);

React Integration

import { OsiseProvider, useOsiseClient, useConsumerProfile, useMutation } from '@osise/api-client/react';
import { BrowserTokenStorage } from '@osise/api-client';

// Wrap your app with the provider
function App() {
  return (
    <OsiseProvider
      config={{
        baseUrl: 'https://api.osise.com',
        storage: new BrowserTokenStorage(),
        onAuthRequired: () => navigate('/login'),
      }}
    >
      <MyApp />
    </OsiseProvider>
  );
}

// Use hooks in components
function Profile() {
  const { data: profile, isLoading, error } = useConsumerProfile();

  if (isLoading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;

  return (
    <div>
      <h1>Welcome, {profile?.firstName}!</h1>
      <p>Phone: {profile?.phoneNumber}</p>
    </div>
  );
}

// Use mutations for actions
function CreateJobButton() {
  const client = useOsiseClient();

  const { mutate, isLoading } = useMutation(
    (data) => client.jobs.create(data),
    {
      onSuccess: (job) => {
        console.log('Job created:', job.id);
      },
      onError: (error) => {
        alert(error.message);
      },
    }
  );

  return (
    <button
      onClick={() => mutate({
        serviceCategory: 'Plumbing',
        title: 'Fix leaky faucet',
        description: 'Kitchen faucet is leaking',
        addressId: 'addr-123',
      })}
      disabled={isLoading}
    >
      Create Job
    </button>
  );
}

React Native Integration

import { OsiseClient, SecureTokenStorage } from '@osise/api-client';
import AsyncStorage from '@react-native-async-storage/async-storage';

// Create secure storage for React Native
const storage = new SecureTokenStorage(AsyncStorage);
await storage.initialize(); // Load tokens from storage

const client = new OsiseClient({
  baseUrl: 'https://api.osise.com',
  storage,
});

API Reference

Authentication

// Request OTP
await client.auth.requestOtp({
  phoneNumber: '+234...',
  purpose: 'Login', // or 'Registration'
  deviceId: 'optional-device-id',
});

// Verify OTP
await client.auth.verifyOtp({
  phoneNumber: '+234...',
  code: '123456',
  deviceId: 'device-id',
  deviceName: 'My Phone',
  deviceType: 'Android',
});

// Register new user
await client.auth.register({
  phoneNumber: '+234...',
  otpCode: '123456',
  firstName: 'John',
  lastName: 'Doe',
  role: 'Consumer',
  deviceId: 'device-id',
});

// Get current user
await client.auth.getCurrentUser();

// Get active sessions
await client.auth.getSessions();

// Revoke a session
await client.auth.revokeSession('session-id');

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

// Logout all sessions
await client.auth.logoutAll();

Consumer Features

// Profile
await client.consumers.getProfile();
await client.consumers.updateProfile({ firstName: 'Jane' });
await client.consumers.uploadProfilePhoto('https://uploadcare.com/...');

// Addresses
await client.consumerAddresses.getAll();
await client.consumerAddresses.create({
  label: 'Home',
  street: '123 Main St',
  area: 'Lekki',
  city: 'Lagos',
  state: 'Lagos',
  latitude: 6.4541,
  longitude: 3.3947,
});
await client.consumerAddresses.setDefault('address-id');

// Favorites
await client.consumers.getFavorites();
await client.consumers.addFavorite('artisan-id');
await client.consumers.removeFavorite('artisan-id');

// Notification Settings
await client.consumers.getNotificationSettings();
await client.consumers.updateNotificationSettings({
  pushEnabled: true,
  jobUpdates: true,
});

// NDPR Compliance
await client.consumers.exportData();
await client.consumers.requestAccountDeletion({ reason: 'Moving abroad' });

Artisan Features

// Profile
await client.artisans.getProfile();
await client.artisans.updateProfile({ bio: 'Experienced plumber' });

// Documents
await client.artisans.getDocuments();
await client.artisans.submitDocument({
  documentType: 'Nin',
  fileUrl: 'https://...',
  fileName: 'nin.pdf',
  fileSize: 1024,
  mimeType: 'application/pdf',
});

// Guarantors
await client.artisans.getGuarantors();
await client.artisans.addGuarantor({
  fullName: 'Jane Smith',
  phoneNumber: '+234...',
  relationship: 'Former Employer',
  occupation: 'Business Owner',
  address: '456 Oak St, Lagos',
});

// Bank Account
await client.artisans.getBankAccount();
await client.artisans.setBankAccount({
  bankCode: '044',
  accountNumber: '0123456789',
  accountName: 'John Doe',
});

// Application Status
await client.artisans.getApplicationStatus();
await client.artisans.getSkillTestSlots();
await client.artisans.bookSkillTest({ slotId: 'slot-id' });

// Availability
await client.artisanAvailability.getStatus();
await client.artisanAvailability.updateStatus({ status: 'Online' });
await client.artisanAvailability.updateWorkingHours({
  workingHours: [
    { dayOfWeek: 'Monday', isWorking: true, startTime: '08:00', endTime: '17:00' },
    // ...
  ],
});
await client.artisanAvailability.updateLocation({ latitude: 6.45, longitude: 3.39 });

// Earnings
await client.artisanEarnings.getSummary();
await client.artisanEarnings.getJobEarnings({ page: 1, pageSize: 20 });
await client.artisanEarnings.getPendingEarnings();
await client.artisanEarnings.getPayouts();

// Performance
await client.artisanPerformance.getRating();
await client.artisanPerformance.getReviews();
await client.artisanPerformance.getMetrics({ period: 'month' });
await client.artisanPerformance.getAlerts();

Jobs

// Consumer - Create and manage jobs
await client.jobs.create({
  serviceCategory: 'Electrical',
  title: 'Fix electrical outlet',
  description: 'Outlet in bedroom not working',
  addressId: 'address-id',
  isUrgent: true,
});

await client.jobs.list({ status: 'Pending', page: 1 });
await client.jobs.get('job-id');
await client.jobs.cancel('job-id', { reason: 'Found another solution' });
await client.jobs.getTimeline('job-id');

// Quotes
await client.jobs.getQuote('job-id');
await client.jobs.respondToQuote('job-id', { decision: 'approve' });

// Payments
await client.jobs.initiatePayment('job-id', { method: 'Card' });
await client.jobs.verifyPayment('job-id', 'payment-reference');

// Ratings
await client.jobs.submitRating('job-id', {
  overall: 5,
  quality: 5,
  punctuality: 4,
  professionalism: 5,
  value: 4,
  reviewText: 'Great work!',
});

// Artisan - Handle assigned jobs
await client.artisanJobs.list({ status: 'Assigned' });
await client.artisanJobs.accept('job-id');
await client.artisanJobs.decline('job-id', 'Too far away');
await client.artisanJobs.startEnRoute('job-id');
await client.artisanJobs.markArrived('job-id', { latitude: 6.45, longitude: 3.39 });
await client.artisanJobs.submitQuote('job-id', {
  laborCost: 5000,
  materials: [
    { item: 'Wire', quantity: 2, unitPrice: 500 },
  ],
  estimatedDuration: '2 hours',
});
await client.artisanJobs.startWork('job-id');
await client.artisanJobs.complete('job-id', 'All fixed');

Admin Features

// Dashboard
await client.adminDashboard.getStats();

// Artisan Management
await client.adminArtisans.list({ search: 'John', status: 'Active' });
await client.adminArtisans.get('artisan-id');
await client.adminArtisans.suspend('artisan-id', 'Policy violation');
await client.adminArtisans.issueStrike('artisan-id', {
  type: 'QualityIssue',
  reason: 'Poor workmanship reported',
  severity: 'warning',
});

// Application Review
await client.adminApplications.list({ verificationStatus: 'DocumentsReview' });
await client.adminApplications.reviewDocument('artisan-id', 'doc-id', {
  status: 'Approved',
});
await client.adminApplications.process('artisan-id', { action: 'approve' });

// Consumer Management
await client.adminConsumers.list({ accountType: 'Business' });
await client.adminConsumers.block('consumer-id', { reason: 'Fraud' });
await client.adminConsumers.unblock('consumer-id');

// Job Management
await client.adminJobs.list();
await client.adminJobs.assignArtisan('job-id', 'artisan-id');
await client.adminJobs.resolveDispute('job-id', 'Refund issued', 5000);

// Service Categories Management
await client.adminServiceCategories.list();
await client.adminServiceCategories.get('category-id');
await client.adminServiceCategories.create({
  name: 'Landscaping',
  description: 'Garden and outdoor maintenance services',
  displayOrder: 10,
});
await client.adminServiceCategories.update('category-id', {
  isActive: true,
  displayOrder: 5,
});
await client.adminServiceCategories.delete('category-id');

Location Services

// Geocode an address to coordinates
const geocodeResult = await client.location.geocode({
  address: '123 Main Street',
  city: 'Lagos',
  state: 'Lagos',
  country: 'Nigeria',
});
console.log('Coordinates:', geocodeResult.data?.latitude, geocodeResult.data?.longitude);

// Reverse geocode coordinates to address
const reverseResult = await client.location.reverseGeocode({
  latitude: 6.5244,
  longitude: 3.3792,
});
console.log('Address:', reverseResult.data?.formattedAddress);

// Calculate distance between two points
const distance = await client.location.calculateDistance({
  originLatitude: 6.5244,
  originLongitude: 3.3792,
  destinationLatitude: 6.4281,
  destinationLongitude: 3.4219,
});
console.log(`Distance: ${distance.data?.distanceKm} km`);
console.log(`Estimated travel time: ${distance.data?.estimatedTravelTimeMinutes} minutes`);

// Get all service areas
const areas = await client.location.getServiceAreas({
  state: 'Lagos',
  city: 'Lekki',
});

// Find nearby service areas
const nearby = await client.location.getNearbyAreas({
  latitude: 6.5244,
  longitude: 3.3792,
  radiusKm: 10,
  limit: 5,
});

// Check if a location is serviced
const serviceCheck = await client.location.checkServiceArea(6.5244, 3.3792);
if (serviceCheck.data?.isServiced) {
  console.log('Location is serviced!');
  console.log('Service Area:', serviceCheck.data.serviceArea);
} else {
  console.log('Location not serviced. Nearby areas:', serviceCheck.data?.nearbyAreas);
}

Error Handling

import { OsiseApiError } from '@osise/api-client';

try {
  await client.auth.verifyOtp({ ... });
} catch (error) {
  if (error instanceof OsiseApiError) {
    if (error.isUnauthorized) {
      // Token expired or invalid
    } else if (error.isValidationError) {
      // Validation failed - check error.errors
      console.log(error.errors);
    } else if (error.isRateLimited) {
      // Too many requests
    } else if (error.isNetworkError) {
      // Network issue
    } else if (error.isTimeoutError) {
      // Request timed out
    }

    console.error(error.message, error.statusCode);
  }
}

TypeScript Support

All types are fully exported:

import type {
  // Auth
  AuthResponseDto,
  UserProfileDto,
  SessionDto,

  // Consumer
  ConsumerProfileDto,
  AddressDto,

  // Artisan
  ArtisanProfileDto,
  ApplicationStatusDto,
  VerificationStatus,

  // Jobs
  JobRequestDto,
  JobStatus,
  Quote,

  // Location
  LocationServiceAreaDto,
  GeocodeRequestDto,
  GeocodeResponseDto,
  ReverseGeocodeRequestDto,
  ReverseGeocodeResponseDto,
  CalculateDistanceRequestDto,
  CalculateDistanceResponseDto,
  ServiceAreaCheckResultDto,

  // Admin
  AdminServiceCategoryDto,
  CreateServiceCategoryDto,
  UpdateServiceCategoryDto,

  // Common
  StandardResponse,
  PagedResult,

  // Enums
  ServiceCategory,
  PaymentMethod,
  AccountType,
} from '@osise/api-client';

Configuration Options

const client = new OsiseClient({
  // Required
  baseUrl: 'https://api.osise.com',

  // Optional
  timeout: 30000, // Request timeout in ms
  storage: new BrowserTokenStorage(), // Token storage
  headers: { 'X-Custom-Header': 'value' }, // Custom headers
  autoRefresh: true, // Auto refresh tokens (default: true)

  // Callbacks
  onError: (error) => console.error(error),
  onAuthRequired: () => redirectToLogin(),
  onTokenRefresh: (accessToken, refreshToken) => {
    console.log('Tokens refreshed');
  },
});

Storage Options

// Browser (localStorage)
import { BrowserTokenStorage } from '@osise/api-client';
const storage = new BrowserTokenStorage('osise'); // optional key prefix

// React Native (AsyncStorage)
import { SecureTokenStorage } from '@osise/api-client';
const storage = new SecureTokenStorage(AsyncStorage);
await storage.initialize();

// In-memory (SSR, testing)
import { MemoryTokenStorage } from '@osise/api-client';
const storage = new MemoryTokenStorage();

License

MIT