Documentation Index
Fetch the complete documentation index at: https://docs.bookovia.com/llms.txt
Use this file to discover all available pages before exploring further.
Bookovia TypeScript SDK
The official TypeScript SDK for the Bookovia Telematics API provides a fully type-safe, modern development experience with comprehensive IntelliSense support and compile-time error checking.Features
- ✅ Full Type Safety - Comprehensive TypeScript definitions
- ✅ Auto-generated Types - Types generated from API schema
- ✅ IntelliSense Support - Complete IDE autocomplete and validation
- ✅ Compile-time Validation - Catch errors before runtime
- ✅ Modern ESM/CommonJS - Support for both module systems
- ✅ Generic Interfaces - Flexible and extensible type system
- ✅ Strict Mode Compatible - Works with strictest TypeScript settings
Installation
npm
npm install @bookovia/typescript-sdk
yarn
yarn add @bookovia/typescript-sdk
- TypeScript 4.5+
- Node.js 16+
- Modern build tools (Vite, Webpack 5, etc.)
Quick Start
Initialize the Client
import { BookoviaClient, ClientConfig } from '@bookovia/typescript-sdk';
// Initialize with API key
const client = new BookoviaClient('bkv_live_your_api_key');
// With typed configuration
const config: ClientConfig = {
baseUrl: 'https://api.bookovia.com/v1',
timeout: 30000,
retryCount: 3,
debug: false
};
const client = new BookoviaClient('bkv_live_your_api_key', config);
Start a Trip with Full Type Safety
import {
StartTripRequest,
Trip,
Location,
TripStatus
} from '@bookovia/typescript-sdk';
async function startTrip(): Promise<Trip> {
const request: StartTripRequest = {
vehicleId: 'vehicle_123',
driverId: 'driver_456', // Optional with proper typing
startLocation: { // Optional with proper typing
latitude: 40.7128,
longitude: -74.0060,
address: 'New York, NY' // Optional
},
metadata: {
purpose: 'delivery',
route: 'downtown',
priority: 'high'
}
};
try {
const trip: Trip = await client.trips.start(request);
console.log(`Trip started: ${trip.tripId}`);
return trip;
} catch (error) {
// Error handling with typed errors
throw error;
}
}
Type-safe Location Upload
import {
LocationUploadRequest,
BatchUploadRequest,
LocationPoint
} from '@bookovia/typescript-sdk';
async function uploadLocations(tripId: string): Promise<void> {
const locations: LocationPoint[] = [
{
latitude: 40.7128,
longitude: -74.0060,
timestamp: new Date().toISOString(),
speed: 35,
heading: 180,
accuracy: 5 // Optional with type checking
},
{
latitude: 40.7130,
longitude: -74.0058,
timestamp: new Date(Date.now() + 30000).toISOString(),
speed: 42,
heading: 175
}
];
const request: BatchUploadRequest = {
tripId,
locations
};
await client.locations.batchUpload(request);
}
Type Definitions
Core Types
// Trip-related types
export interface Trip {
readonly tripId: string;
readonly organizationId: string;
readonly vehicleId: string;
readonly driverId?: string;
readonly status: TripStatus;
readonly startTime: string; // ISO 8601
readonly endTime?: string;
readonly startLocation?: Location;
readonly endLocation?: Location;
readonly analytics: TripAnalytics;
readonly metadata?: Record<string, unknown>;
readonly createdAt: string;
readonly updatedAt: string;
}
export interface Location {
readonly latitude: number;
readonly longitude: number;
readonly address?: string;
}
export interface LocationPoint extends Location {
readonly timestamp: string; // ISO 8601
readonly speed: number; // km/h
readonly heading: number; // 0-360 degrees
readonly accuracy?: number; // meters
readonly altitude?: number; // meters
}
export interface TripAnalytics {
readonly distanceKm: number;
readonly durationMinutes: number;
readonly maxSpeedKmh: number;
readonly avgSpeedKmh: number;
readonly idleTimeMinutes: number;
readonly locationsCount: number;
readonly eventsCount: number;
readonly safetyScore: number; // 0-100
readonly ecoScore: number; // 0-100
}
Enums and Union Types
// Trip status enum
export enum TripStatus {
Active = 'active',
Completed = 'completed',
Paused = 'paused',
Cancelled = 'cancelled'
}
// Event types
export enum EventType {
HarshAcceleration = 'harsh_acceleration',
HarshBraking = 'harsh_braking',
HarshCornering = 'harsh_cornering',
Speeding = 'speeding',
IdleExcessive = 'idle_excessive',
PhoneUsage = 'phone_usage'
}
// Severity levels
export type EventSeverity = 'low' | 'medium' | 'high' | 'critical';
// API environments
export type Environment = 'test' | 'live';
Request Types
export interface StartTripRequest {
readonly vehicleId: string;
readonly driverId?: string;
readonly startLocation?: Location;
readonly metadata?: Record<string, unknown>;
readonly odometerReading?: number;
readonly fuelLevelPercent?: number;
}
export interface StopTripRequest {
readonly endLocation?: Location;
readonly odometerReading?: number;
readonly fuelLevelPercent?: number;
readonly metadata?: Record<string, unknown>;
}
export interface TripFilters {
readonly vehicleId?: string;
readonly driverId?: string;
readonly status?: TripStatus;
readonly startDate?: string; // ISO 8601 date
readonly endDate?: string; // ISO 8601 date
readonly limit?: number; // 1-100
readonly offset?: number; // >= 0
}
export interface LocationUploadRequest {
readonly tripId: string;
readonly latitude: number;
readonly longitude: number;
readonly timestamp: string;
readonly speed: number;
readonly heading: number;
readonly accuracy?: number;
readonly altitude?: number;
}
export interface BatchUploadRequest {
readonly tripId: string;
readonly locations: readonly LocationPoint[];
}
Response Types
export interface TripListResponse {
readonly trips: readonly Trip[];
readonly totalCount: number;
readonly hasMore: boolean;
readonly nextOffset?: number;
}
export interface SafetyScore {
readonly score: number; // 0-100
readonly grade: 'A' | 'B' | 'C' | 'D' | 'F';
readonly factors: readonly SafetyFactor[];
readonly recommendations: readonly string[];
readonly period: {
readonly start: string;
readonly end: string;
};
}
export interface SafetyFactor {
readonly category: string;
readonly score: number;
readonly weight: number;
readonly description: string;
}
export interface Event {
readonly eventId: string;
readonly tripId: string;
readonly eventType: EventType;
readonly severity: EventSeverity;
readonly timestamp: string;
readonly location: Location;
readonly details: Record<string, unknown>;
readonly processed: boolean;
}
Client Configuration Types
export interface ClientConfig {
readonly baseUrl?: string;
readonly timeout?: number;
readonly retryCount?: number;
readonly retryDelay?: number;
readonly debug?: boolean;
readonly defaultHeaders?: Record<string, string>;
readonly requestInterceptor?: RequestInterceptor;
readonly responseInterceptor?: ResponseInterceptor;
}
export type RequestInterceptor = (config: RequestConfig) => RequestConfig | Promise<RequestConfig>;
export type ResponseInterceptor = (response: ApiResponse) => ApiResponse | Promise<ApiResponse>;
export interface RequestConfig {
readonly method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
readonly url: string;
readonly headers: Record<string, string>;
readonly data?: unknown;
readonly params?: Record<string, string | number>;
}
export interface ApiResponse<T = unknown> {
readonly data: T;
readonly status: number;
readonly statusText: string;
readonly headers: Record<string, string>;
readonly requestId?: string;
readonly responseTime?: number;
}
Service Interfaces
Trip Service
export interface TripService {
// User Trip Queries
getUserActiveTrips(userId: string): Promise<TelematicsResult<any>>;
getUserTripHistory(userId: string, status?: string): Promise<TelematicsResult<any>>;
// Organization Trip Queries
getOrgActiveTrips(orgId: string): Promise<TelematicsResult<any>>;
getOrgTripHistory(orgId: string, status?: string): Promise<TelematicsResult<any>>;
// Vehicle Trip Queries
getVehicleActiveTrips(vehicleId: string): Promise<TelematicsResult<any>>;
getVehicleTripHistory(vehicleId: string, status?: string): Promise<TelematicsResult<any>>;
// Legacy Methods
start(request: StartTripRequest): Promise<Trip>;
stop(tripId: string, request?: StopTripRequest): Promise<Trip>;
get(tripId: string): Promise<Trip>;
list(filters?: TripFilters): Promise<TripListResponse>;
getSummary(tripId: string): Promise<TripSummary>;
updateMetadata(tripId: string, metadata: Record<string, unknown>): Promise<Trip>;
}
Location Service
export interface LocationService {
upload(request: LocationUploadRequest): Promise<void>;
batchUpload(request: BatchUploadRequest): Promise<BatchUploadResponse>;
getRoute(tripId: string): Promise<Route>;
findNearby(request: NearbySearchRequest): Promise<NearbyLocation[]>;
}
export interface BatchUploadResponse {
readonly accepted: number;
readonly rejected: number;
readonly errors: readonly ValidationError[];
}
export interface Route {
readonly tripId: string;
readonly coordinates: readonly [number, number][]; // [lng, lat] tuples
readonly distance: number;
readonly duration: number;
readonly boundingBox: readonly [number, number, number, number]; // [minLng, minLat, maxLng, maxLat]
}
Safety Service
export interface SafetyService {
getScore(request: SafetyScoreRequest): Promise<SafetyScore>;
analyzeBehavior(request: BehaviorAnalysisRequest): Promise<BehaviorAnalysis>;
getHarshEvents(filters: EventFilters): Promise<EventListResponse>;
getCrashRisk(request: CrashRiskRequest): Promise<CrashRiskAssessment>;
}
export interface SafetyScoreRequest {
readonly tripId?: string;
readonly driverId?: string;
readonly vehicleId?: string;
readonly dateRange?: DateRange;
}
export interface DateRange {
readonly start: string; // ISO 8601 date
readonly end: string; // ISO 8601 date
}
export interface BehaviorAnalysis {
readonly driverId: string;
readonly period: DateRange;
readonly metrics: {
readonly harshAccelerationRate: number;
readonly harshBrakingRate: number;
readonly speedingRate: number;
readonly phoneUsageRate: number;
};
readonly improvements: readonly string[];
readonly trends: readonly BehaviorTrend[];
}
export interface BehaviorTrend {
readonly metric: string;
readonly change: number; // Percentage change
readonly direction: 'improving' | 'declining' | 'stable';
}
Error Handling with Types
import {
BookoviaError,
AuthenticationError,
ValidationError,
NotFoundError,
RateLimitError,
ServerError
} from '@bookovia/typescript-sdk';
async function handleTripCreation(request: StartTripRequest): Promise<Trip | null> {
try {
return await client.trips.start(request);
} catch (error) {
if (error instanceof AuthenticationError) {
console.error('Authentication failed:', error.message);
// Handle auth error with proper typing
return null;
} else if (error instanceof ValidationError) {
console.error('Validation errors:', error.fields);
// error.fields is properly typed as ValidationField[]
error.fields.forEach(field => {
console.error(`${field.path}: ${field.message}`);
});
return null;
} else if (error instanceof RateLimitError) {
console.error(`Rate limited. Retry after: ${error.retryAfter}ms`);
// error.retryAfter is typed as number
return null;
} else if (error instanceof NotFoundError) {
console.error('Resource not found:', error.resourceType, error.resourceId);
return null;
} else {
// Generic error handling
console.error('Unexpected error:', error);
throw error;
}
}
}
// Custom error types for specific domains
export interface ValidationField {
readonly path: string;
readonly message: string;
readonly value: unknown;
}
Generic and Advanced Types
Generic Response Wrapper
// Generic API response wrapper
export interface ApiResult<T> {
readonly data: T;
readonly success: boolean;
readonly requestId: string;
readonly timestamp: string;
}
// Paginated response type
export interface PaginatedResponse<T> {
readonly items: readonly T[];
readonly totalCount: number;
readonly page: number;
readonly pageSize: number;
readonly hasMore: boolean;
}
// Usage with trips
type TripPage = PaginatedResponse<Trip>;
Advanced Type Utilities
// Utility types for common operations
export type PartialUpdate<T> = Partial<Omit<T, 'id' | 'createdAt' | 'updatedAt'>>;
export type CreateRequest<T> = Omit<T, 'id' | 'createdAt' | 'updatedAt'>;
export type ReadOnlyFields<T> = Pick<T, 'id' | 'createdAt' | 'updatedAt'>;
// Example usage
type TripUpdate = PartialUpdate<Trip>; // Only allows updating mutable fields
type NewTrip = CreateRequest<Trip>; // Excludes system-generated fields
// Conditional types for different API environments
export type ApiKey<T extends Environment> = T extends 'test'
? `bkv_test_${string}`
: `bkv_live_${string}`;
// Usage
const testKey: ApiKey<'test'> = 'bkv_test_1234...'; // ✅ Valid
const liveKey: ApiKey<'live'> = 'bkv_live_5678...'; // ✅ Valid
// const invalid: ApiKey<'test'> = 'bkv_live_1234...'; // ❌ Type error
Advanced Usage Examples
Type-safe Fleet Management
import {
BookoviaClient,
Trip,
TripStatus,
Vehicle,
Driver
} from '@bookovia/typescript-sdk';
class FleetManager {
private client: BookoviaClient;
private activeTrips: Map<string, Trip> = new Map();
constructor(apiKey: string) {
this.client = new BookoviaClient(apiKey);
}
async startFleetOperation(
vehicles: readonly Vehicle[],
drivers: readonly Driver[]
): Promise<Trip[]> {
const trips: Trip[] = [];
for (let i = 0; i < Math.min(vehicles.length, drivers.length); i++) {
const vehicle = vehicles[i];
const driver = drivers[i];
try {
const trip = await this.client.trips.start({
vehicleId: vehicle.vehicleId,
driverId: driver.driverId,
metadata: {
fleetOperation: true,
assignedAt: new Date().toISOString(),
priority: vehicle.priority ?? 'normal'
}
});
this.activeTrips.set(trip.tripId, trip);
trips.push(trip);
} catch (error) {
console.error(`Failed to start trip for vehicle ${vehicle.vehicleId}:`, error);
}
}
return trips;
}
async getFleetStatus(): Promise<FleetStatus> {
const trips = Array.from(this.activeTrips.values());
return {
totalTrips: trips.length,
totalDistance: trips.reduce((sum, trip) => sum + trip.analytics.distanceKm, 0),
averageSpeed: this.calculateAverageSpeed(trips),
safetyScore: this.calculateFleetSafetyScore(trips),
activeVehicles: new Set(trips.map(trip => trip.vehicleId)).size
};
}
private calculateAverageSpeed(trips: readonly Trip[]): number {
const validSpeeds = trips
.map(trip => trip.analytics.avgSpeedKmh)
.filter(speed => speed > 0);
return validSpeeds.length > 0
? validSpeeds.reduce((sum, speed) => sum + speed, 0) / validSpeeds.length
: 0;
}
private calculateFleetSafetyScore(trips: readonly Trip[]): number {
const validScores = trips
.map(trip => trip.analytics.safetyScore)
.filter(score => score > 0);
return validScores.length > 0
? validScores.reduce((sum, score) => sum + score, 0) / validScores.length
: 0;
}
}
interface Vehicle {
readonly vehicleId: string;
readonly model: string;
readonly year: number;
readonly priority?: 'low' | 'normal' | 'high';
}
interface Driver {
readonly driverId: string;
readonly name: string;
readonly licenseNumber: string;
readonly experienceYears: number;
}
interface FleetStatus {
readonly totalTrips: number;
readonly totalDistance: number;
readonly averageSpeed: number;
readonly safetyScore: number;
readonly activeVehicles: number;
}
Real-time Type-safe Location Tracking
import { LocationPoint, BatchUploadRequest } from '@bookovia/typescript-sdk';
class LocationTracker {
private client: BookoviaClient;
private locationBuffer: LocationPoint[] = [];
private intervalId: NodeJS.Timeout | null = null;
constructor(client: BookoviaClient) {
this.client = client;
}
startTracking(tripId: string, options: TrackingOptions = {}): void {
const {
uploadInterval = 30000,
bufferSize = 10,
enableHighAccuracy = true
} = options;
this.intervalId = setInterval(async () => {
try {
const location = await this.getCurrentLocation(enableHighAccuracy);
this.locationBuffer.push(location);
if (this.locationBuffer.length >= bufferSize) {
await this.uploadBufferedLocations(tripId);
}
} catch (error) {
console.error('Location tracking error:', error);
}
}, uploadInterval);
}
stopTracking(): void {
if (this.intervalId) {
clearInterval(this.intervalId);
this.intervalId = null;
}
}
private async getCurrentLocation(enableHighAccuracy: boolean): Promise<LocationPoint> {
return new Promise((resolve, reject) => {
navigator.geolocation.getCurrentPosition(
(position) => {
const location: LocationPoint = {
latitude: position.coords.latitude,
longitude: position.coords.longitude,
timestamp: new Date().toISOString(),
speed: position.coords.speed ?? 0,
heading: position.coords.heading ?? 0,
accuracy: position.coords.accuracy,
altitude: position.coords.altitude ?? undefined
};
resolve(location);
},
reject,
{ enableHighAccuracy, timeout: 10000, maximumAge: 30000 }
);
});
}
private async uploadBufferedLocations(tripId: string): Promise<void> {
if (this.locationBuffer.length === 0) return;
const request: BatchUploadRequest = {
tripId,
locations: [...this.locationBuffer] // Create immutable copy
};
try {
await this.client.locations.batchUpload(request);
this.locationBuffer = []; // Clear buffer after successful upload
} catch (error) {
console.error('Failed to upload locations:', error);
// Keep locations in buffer for retry
}
}
}
interface TrackingOptions {
readonly uploadInterval?: number;
readonly bufferSize?: number;
readonly enableHighAccuracy?: boolean;
}
Testing with Types
Jest Type Testing
// __tests__/types.test.ts
import { BookoviaClient, Trip, StartTripRequest } from '@bookovia/typescript-sdk';
describe('Bookovia TypeScript SDK', () => {
let client: BookoviaClient;
beforeEach(() => {
client = new BookoviaClient('bkv_test_example_key');
});
test('should provide correct types for trip creation', async () => {
// Type-safe request
const request: StartTripRequest = {
vehicleId: 'vehicle_123',
driverId: 'driver_456',
startLocation: {
latitude: 40.7128,
longitude: -74.0060
}
};
// Mock the response with correct typing
const mockTrip: Trip = {
tripId: 'trip_123',
organizationId: 'org_456',
vehicleId: 'vehicle_123',
driverId: 'driver_456',
status: 'active' as const,
startTime: '2024-04-13T10:30:00Z',
startLocation: {
latitude: 40.7128,
longitude: -74.0060
},
analytics: {
distanceKm: 0,
durationMinutes: 0,
maxSpeedKmh: 0,
avgSpeedKmh: 0,
idleTimeMinutes: 0,
locationsCount: 0,
eventsCount: 0,
safetyScore: 100,
ecoScore: 100
},
createdAt: '2024-04-13T10:30:00Z',
updatedAt: '2024-04-13T10:30:00Z'
};
jest.spyOn(client.trips, 'start').mockResolvedValue(mockTrip);
const result = await client.trips.start(request);
// TypeScript ensures result has correct type
expect(result.tripId).toBe('trip_123');
expect(result.status).toBe('active');
});
test('should enforce type safety at compile time', () => {
// These would cause TypeScript compilation errors:
// const invalidRequest: StartTripRequest = {
// vehicleId: 123, // ❌ Should be string
// invalidField: 'value' // ❌ Unknown field
// };
// const trip: Trip = {
// tripId: 'trip_123'
// // ❌ Missing required fields
// };
});
});
IDE Configuration
VSCode Settings
// .vscode/settings.json
{
"typescript.preferences.strict": true,
"typescript.preferences.noImplicitAny": true,
"typescript.preferences.strictNullChecks": true,
"editor.codeActionsOnSave": {
"source.organizeImports": true,
"source.fixAll.eslint": true
}
}
TypeScript Configuration
// tsconfig.json
{
"compilerOptions": {
"target": "ES2020",
"lib": ["ES2020", "DOM"],
"module": "ESNext",
"moduleResolution": "node",
"strict": true,
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"noImplicitReturns": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"exactOptionalPropertyTypes": true
}
}
Support
- npm Package: @bookovia/typescript-sdk
- GitHub: github.com/bookovia/typescript-sdk
- Type Definitions: Included in package
- Issues: GitHub Issues
- Email: support@bookovia.com
Ready for type-safe integration? Check out our quickstart guide and API reference for more examples.