@routeflow/sdk
v1.0.6
Published
TypeScript SDK with TanStack Query hooks for RouteFlow API
Readme
@routeflow/sdk
TypeScript SDK with TanStack Query hooks for the RouteFlow API.
Installation
npm install @routeflow/sdk @tanstack/react-query
# or
yarn add @routeflow/sdk @tanstack/react-query
# or
pnpm add @routeflow/sdk @tanstack/react-querySetup
1. Configure the SDK
Configure the SDK at your app's entry point:
// app/providers.tsx or similar
import { configureSDK } from '@routeflow/sdk';
configureSDK({
baseURL: process.env.NEXT_PUBLIC_API_URL || 'http://localhost:3001',
getAccessToken: () => {
if (typeof window !== 'undefined') {
return localStorage.getItem('accessToken');
}
return null;
},
refreshAccessToken: async () => {
// Implement token refresh logic
const refreshToken = localStorage.getItem('refreshToken');
if (!refreshToken) return null;
const response = await fetch('/api/auth/refresh', {
method: 'POST',
body: JSON.stringify({ refreshToken }),
});
const data = await response.json();
localStorage.setItem('accessToken', data.accessToken);
return data.accessToken;
},
onUnauthorized: () => {
// Redirect to login
window.location.href = '/login';
},
});2. Set up TanStack Query Provider
// app/providers.tsx
'use client';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { useState } from 'react';
export function Providers({ children }: { children: React.ReactNode }) {
const [queryClient] = useState(() => new QueryClient({
defaultOptions: {
queries: {
staleTime: 60 * 1000, // 1 minute
retry: 1,
},
},
}));
return (
<QueryClientProvider client={queryClient}>
{children}
</QueryClientProvider>
);
}Usage
Query Hooks (GET operations)
import { useRuns, useRun, useDrivers, useCurrentUser } from '@routeflow/sdk';
// Get paginated list of runs
function RunsList() {
const { data, isLoading, error } = useRuns({
status: 'IN_PROGRESS',
page: 1,
limit: 10,
});
if (isLoading) return <Loading />;
if (error) return <Error message={error.message} />;
return (
<ul>
{data?.data.map(run => (
<li key={run.id}>{run.name}</li>
))}
</ul>
);
}
// Get single run
function RunDetail({ runId }: { runId: string }) {
const { data: run, isLoading } = useRun(runId);
// ...
}
// Get current user
function Profile() {
const { data: user, isLoading } = useCurrentUser();
// ...
}
// Get drivers
function DriversList() {
const { data: drivers } = useDrivers({ onlineOnly: true });
// ...
}Mutation Hooks (POST/PUT/DELETE operations)
import {
useCreateRun,
useUpdateRun,
useDeleteRun,
useAssignDriver,
useLogin,
useLogout,
} from '@routeflow/sdk';
// Create a run
function CreateRunForm() {
const { mutate: createRun, isPending } = useCreateRun({
onSuccess: (run) => {
console.log('Created run:', run.id);
router.push(`/runs/${run.id}`);
},
onError: (error) => {
toast.error(error.message);
},
});
const handleSubmit = (data: CreateRunRequest) => {
createRun(data);
};
return <form onSubmit={handleSubmit}>...</form>;
}
// Update a run
function EditRunForm({ runId }: { runId: string }) {
const { mutate: updateRun, isPending } = useUpdateRun();
const handleSave = (data: UpdateRunRequest) => {
updateRun({ id: runId, data });
};
}
// Delete a run
function DeleteRunButton({ runId }: { runId: string }) {
const { mutate: deleteRun, isPending } = useDeleteRun({
onSuccess: () => router.push('/runs'),
});
return (
<button onClick={() => deleteRun(runId)} disabled={isPending}>
Delete
</button>
);
}
// Assign driver
function AssignDriverSelect({ runId }: { runId: string }) {
const { mutate: assignDriver } = useAssignDriver();
return (
<select onChange={(e) => assignDriver({ runId, driverId: e.target.value })}>
...
</select>
);
}
// Login
function LoginForm() {
const { mutate: login, isPending, error } = useLogin({
onSuccess: (data) => {
localStorage.setItem('accessToken', data.accessToken);
localStorage.setItem('refreshToken', data.refreshToken);
router.push('/dashboard');
},
});
return (
<form onSubmit={(e) => {
e.preventDefault();
login({ email, password });
}}>
...
</form>
);
}Tracking (Public API)
import { useTrackingStatus, useTrackingLocation } from '@routeflow/sdk';
// Public tracking page
function TrackingPage({ token }: { token: string }) {
const { data: status, isLoading: statusLoading } = useTrackingStatus(token);
const { data: location, isLoading: locationLoading } = useTrackingLocation(token);
if (statusLoading) return <Loading />;
return (
<div>
<h1>{status?.runName}</h1>
<p>Status: {status?.status}</p>
<p>ETA: {status?.eta?.estimatedTime}</p>
{location?.available && (
<Map lat={location.location.lat} lng={location.location.lng} />
)}
</div>
);
}Available Hooks
Queries
useCurrentUser()- Get authenticated useruseRuns(params?)- List runs with pagination/filtersuseRun(id)- Get single runuseDrivers(params?)- List driversuseDriver(id)- Get single driveruseTrackingStatus(token)- Public tracking statususeTrackingLocation(token)- Public driver location
Mutations
useLogin()- LoginuseRegister()- RegisteruseLogout()- LogoutuseCreateRun()- Create runuseUpdateRun()- Update runuseDeleteRun()- Delete runuseAssignDriver()- Assign driver to runuseUnassignDriver()- Remove driver from runuseStartRun()- Start runuseCompleteRun()- Complete runuseOptimizeRoute()- Optimize run routeuseCreateStop()- Add stop to runuseUpdateStop()- Update stopuseDeleteStop()- Delete stopuseUpdateStopStatus()- Update stop statususeReorderStops()- Reorder stops
Types
All types are re-exported from @routeflow/types:
import type {
Run,
Stop,
Driver,
User,
RunStatus,
StopStatus,
ApiResponse,
PaginatedResponse,
} from '@routeflow/sdk';Query Keys
For manual cache invalidation:
import { queryKeys } from '@routeflow/sdk';
import { useQueryClient } from '@tanstack/react-query';
const queryClient = useQueryClient();
// Invalidate all runs
queryClient.invalidateQueries({ queryKey: queryKeys.runs.all });
// Invalidate specific run
queryClient.invalidateQueries({ queryKey: queryKeys.runs.detail('run-123') });
// Invalidate all drivers
queryClient.invalidateQueries({ queryKey: queryKeys.drivers.all });License
MIT
