npm package: @routeflow/sdk
Description: TypeScript SDK with TanStack Query hooks for RouteFlow API
Author: S2S Engineering
Latest version: 1.0.54

# @routeflow/sdk

TypeScript SDK with TanStack Query hooks for the RouteFlow API.

## Installation

```bash
npm install @routeflow/sdk @tanstack/react-query
# or
yarn add @routeflow/sdk @tanstack/react-query
# or
pnpm add @routeflow/sdk @tanstack/react-query
```

## Setup

### 1. Configure the SDK

Configure the SDK at your app's entry point:

```typescript
// 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

```typescript
// 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)

```typescript
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)

```typescript
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)

```typescript
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 user
- `useRuns(params?)` - List runs with pagination/filters
- `useRun(id)` - Get single run
- `useDrivers(params?)` - List drivers
- `useDriver(id)` - Get single driver
- `useTrackingStatus(token)` - Public tracking status
- `useTrackingLocation(token)` - Public driver location

### Mutations
- `useLogin()` - Login
- `useRegister()` - Register
- `useLogout()` - Logout
- `useCreateRun()` - Create run
- `useUpdateRun()` - Update run
- `useDeleteRun()` - Delete run
- `useAssignDriver()` - Assign driver to run
- `useUnassignDriver()` - Remove driver from run
- `useStartRun()` - Start run
- `useCompleteRun()` - Complete run
- `useOptimizeRoute()` - Optimize run route
- `useCreateStop()` - Add stop to run
- `useUpdateStop()` - Update stop
- `useDeleteStop()` - Delete stop
- `useUpdateStopStatus()` - Update stop status
- `useReorderStops()` - Reorder stops

## Types

All types are re-exported from `@routeflow/types`:

```typescript
import type {
  Run,
  Stop,
  Driver,
  User,
  RunStatus,
  StopStatus,
  ApiResponse,
  PaginatedResponse,
} from '@routeflow/sdk';
```

## Query Keys

For manual cache invalidation:

```typescript
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