ws-dottie
Version:
Your friendly TypeScript companion for Washington State transportation APIs - WSDOT and WSF data with smart caching and React Query integration
1,020 lines (769 loc) β’ 30.8 kB
Markdown
# API Reference
Complete reference for WS-Dottie's APIs and utilities.
## π¦ Package Structure
WS-Dottie is a single package that provides everything you need:
```javascript
import {
// API modules
WsfVessels,
WsdotHighwayAlerts,
// React hooks
useVesselLocations,
useHighwayAlerts,
// Configuration
configManager,
tanstackQueryOptions,
// Error handling
ApiError,
// Types
VesselLocation,
HighwayAlert
} from 'ws-dottie';
```
## π Configuration
WS-Dottie requires a WSDOT API key to access transportation data. Get your free key from the [WSDOT Developer Portal](https://wsdot.wa.gov/developers/api-access).
### Environment Variables (Recommended)
```bash
export WSDOT_ACCESS_TOKEN=your_api_key_here
```
#### Runtime Configuration
For web applications or dynamic environments:
```javascript
import { configManager } from 'ws-dottie';
// Set API key only (recommended for web clients)
configManager.setApiKey('your_api_key_here');
// Set base URL only (optional: route through proxy)
configManager.setBaseUrl('https://your-proxy-server.com');
// Clear configuration (useful for testing)
configManager.clearConfig();
```
### Configuration Interface
WS-Dottie provides a type-safe configuration interface:
```javascript
import { configManager } from 'ws-dottie';
// Type-safe configuration interface
interface WsdotConfig {
WSDOT_ACCESS_TOKEN: string;
WSDOT_BASE_URL?: string;
}
// Set configuration at runtime
configManager.setConfig({
WSDOT_ACCESS_TOKEN: 'your_api_key_here',
WSDOT_BASE_URL: 'https://your-proxy-server.com' // Optional
});
// Get current configuration
const apiKey = configManager.getApiKey();
const baseUrl = configManager.getBaseUrl();
// Clear configuration (useful for testing)
configManager.clearConfig();
```
## π¦ Module Format Support
WS-Dottie supports both CommonJS and ES Module formats:
### ES Modules (Recommended)
```javascript
import { useVesselLocations, useHighwayAlerts, configManager, tanstackQueryOptions } from 'ws-dottie';
```
### CommonJS
```javascript
const { useVesselLocations, useHighwayAlerts, configManager, tanstackQueryOptions } = require('ws-dottie');
```
The library automatically provides the appropriate format based on your environment. Modern bundlers and Node.js will choose the optimal format automatically.
## π Debugging and Logging
WS-Dottie includes optional logging to help you troubleshoot API calls:
```javascript
import { WsfVessels } from 'ws-dottie';
// Enable debug logging for a specific call
const vessels = await WsfVessels.getVesselLocations();
// Or use info-level logging
const alerts = await WsdotHighwayAlerts.getHighwayAlerts();
```
Logging modes:
- `'debug'` - Detailed request/response information (console.debug in development)
- `'info'` - Basic request information
- `'none'` - No logging (default)
## π Advanced Caching Configuration
WS-Dottie includes optimized caching strategies for different data types:
```javascript
import { tanstackQueryOptions } from 'ws-dottie';
// Real-time data (5-second updates)
const realtimeConfig = tanstackQueryOptions.REALTIME_UPDATES;
// Minute updates (1-minute intervals)
const minuteConfig = tanstackQueryOptions.MINUTE_UPDATES;
// Hourly updates (1-hour intervals)
const hourlyConfig = tanstackQueryOptions.HOURLY_UPDATES;
// Daily updates (24-hour intervals)
const dailyConfig = tanstackQueryOptions.DAILY_UPDATES;
// Weekly updates (manual refresh only)
const weeklyConfig = tanstackQueryOptions.WEEKLY_UPDATES;
```
### Caching Strategy Details
| Strategy | Stale Time | GC Time | Refetch Interval | Retry |
|----------|------------|---------|------------------|-------|
| REALTIME_UPDATES | 5s | 1h | 5s | 1 (2s delay) |
| MINUTE_UPDATES | 1m | 1h | 1m | false |
| HOURLY_UPDATES | 1h | 4h | 1h | 5 (30s..2m backoff) |
| DAILY_UPDATES | 1d | 2d | 1d | 5 (1m..10m backoff) |
| WEEKLY_UPDATES | 1w | 2w | false | 5 (1m..10m backoff) |
### Custom Caching
You can override the default caching behavior:
```javascript
import { useVesselLocations } from 'ws-dottie';
function CustomVesselApp() {
const { data: vessels } = useVesselLocations({
staleTime: 5 * 1000, // 5 seconds
refetchInterval: 10 * 1000, // 10 seconds
});
return <div>Vessels: {vessels?.length}</div>;
}
```
### Advanced Caching Customization
WSβDottie's caching strategies can be customized using spread operators with TanStack Query options. These are plain TanStack Query options (not WSβDottie specific):
```typescript
import { useVesselLocations, tanstackQueryOptions } from 'ws-dottie';
function AdvancedVesselTracker() {
const { data: vessels } = useVesselLocations({
// Start with a WSβDottie preset
...tanstackQueryOptions.REALTIME_UPDATES,
// Override with regular TanStack Query options:
refetchInterval: 30_000, // poll every 30s
refetchOnWindowFocus: false, // don't refetch on focus
staleTime: 15_000, // data fresh for 15s
gcTime: 2 * 60 * 60 * 1000, // keep 2h in cache
retry: 2, // two retries
retryDelay: attempt => Math.min(2000 * 2 ** attempt, 15000),
// Useful real-world toggles:
refetchOnReconnect: 'always', // refetch after reconnect
refetchOnMount: false, // skip refetch on mount if data fresh
placeholderData: previous => previous, // show previous data during refetch
// Per-query selection with type inference
select: data => data?.slice(0, 20),
});
return (
<div>
<h2>Vessels (customized)</h2>
{vessels?.map(v => (
<div key={v.VesselID}>{v.VesselName}</div>
))}
</div>
);
}
```
This approach allows you to:
- **Extend base strategies** - Start with a predefined strategy and customize specific options
- **Mix and match** - Combine different aspects of various strategies
- **Fine-tune performance** - Optimize caching for your specific use case
- **Maintain consistency** - Keep the base strategy's proven defaults while customizing only what you need
## π― Strong Typing
WS-Dottie provides comprehensive TypeScript types for all APIs, parameters, and responses with **automatic type inference**:
```typescript
import {
WsfVessels,
WsdotHighwayAlerts,
VesselLocation,
HighwayAlert
} from 'ws-dottie';
// All API functions are fully typed
const vessels: VesselLocation[] = await WsfVessels.getVesselLocations();
const alerts: HighwayAlert[] = await WsdotHighwayAlerts.getHighwayAlerts();
// Parameter objects are strongly typed
const camera = await WsdotHighwayCameras.getCamera({ cameraID: 1001 });
const fares = await WsfFares.getFareLineItems({
tripDate: new Date('2024-01-15'),
departingTerminalID: 7,
arrivingTerminalID: 8,
roundTrip: false
});
// React hooks provide automatic type inference - no manual typing needed!
const { data: hookVessels } = useVesselLocations(); // TypeScript knows: VesselLocation[] | undefined
const { data: hookAlerts } = useHighwayAlerts(); // TypeScript knows: HighwayAlert[] | undefined
```
### Type Safety Features
- **Automatic Type Inference** - React hooks automatically infer return types without manual annotations
- **Parameter Objects** - All API calls use consistent single-parameter object patterns
- **Response Types** - All API responses are fully typed with TypeScript interfaces
- **Error Types** - Consistent error handling with typed error objects
- **Configuration Types** - Type-safe configuration interface
- **TanStack Query Integration** - Seamless compatibility with all TanStack Query features
## π§© Consistent Parameter Object Pattern
All WS-Dottie fetch functions and React hooks use a **single, optional, strongly-typed options parameter**. This pattern ensures consistency, type safety, and extensibility across the entire library.
**Example:**
```typescript
// Fetch function
const camera = await WsdotHighwayCameras.getCamera({ cameraID: 1001 });
// React hook
const { data: camera } = useHighwayCamera({ cameraID: 1001 });
```
- If no parameters are required, you may call the function with no arguments or with an empty object: `getBorderCrossings()` or `getBorderCrossings({})`.
- All parameters are passed as named properties of the options object.
- All options are fully type-checked with TypeScript.
## π¦ Parameter Object Pattern
All WS-Dottie API functions use a consistent parameter object pattern for better maintainability and type safety:
```javascript
import { WsdotHighwayCameras, WsfFares } from 'ws-dottie';
// Single parameter object for all API calls
const camera = await WsdotHighwayCameras.getCamera({
cameraID: 1001
});
const searchResults = await WsdotHighwayCameras.searchCameras({
StateRoute: "5",
Region: "Northwest"
});
const fares = await WsfFares.getFareLineItems({
tripDate: new Date('2024-01-15'),
departingTerminalID: 7,
arrivingTerminalID: 8,
roundTrip: false
});
```
This pattern provides:
- **Consistency** - All APIs follow the same parameter structure
- **Type Safety** - TypeScript ensures correct parameter types
- **Extensibility** - Easy to add optional parameters without breaking changes
- **Readability** - Clear parameter names and structure
## π― API Modules
### WSF (Washington State Ferries) APIs
#### Vessels API
```javascript
import { WsfVessels } from 'ws-dottie';
// Get all vessel locations
const vessels = await WsfVessels.getVesselLocations();
// Get vessel details with logging
const vessel = await WsfVessels.getVesselVerboseById({ vesselId: 123 });
// Get vessel history for a specific vessel and date range
const history = await WsfVessels.getVesselHistoryByVesselAndDateRange({
vesselName: "Spokane",
dateStart: new Date("2024-01-01"),
dateEnd: new Date("2024-01-02")
});
// Get vessel statistics
const stats = await WsfVessels.getVesselStatsById({ vesselId: 123 });
// Get vessel accommodations
const accommodations = await WsfVessels.getVesselAccommodationsById({ vesselId: 123 });
// Get cache flush date
const flushDate = await WsfVessels.getCacheFlushDate();
```
#### Terminals API
```javascript
import { WsfTerminals } from 'ws-dottie';
// Get terminal basics
const terminals = await WsfTerminals.getTerminalBasics();
// Get terminal wait times
const waitTimes = await WsfTerminals.getTerminalWaitTimes();
// Get terminal locations
const locations = await WsfTerminals.getTerminalLocations();
// Get terminal sailing space
const sailingSpace = await WsfTerminals.getTerminalSailingSpace();
// Get terminal transports
const transports = await WsfTerminals.getTerminalTransports();
// Get terminal bulletins
const bulletins = await WsfTerminals.getTerminalBulletins();
// Get terminal verbose data
const verbose = await WsfTerminals.getTerminalVerbose();
// Get cache flush date
const flushDate = await WsfTerminals.getCacheFlushDate();
```
#### Schedule API
```javascript
import { WsfSchedule } from 'ws-dottie';
// Get all routes
const routes = await WsfSchedule.getRoutes();
// Get scheduled routes
const scheduledRoutes = await WsfSchedule.getScheduledRoutes();
// Get schedules for a route
const schedules = await WsfSchedule.getSchedulesByRoute({ routeId: 123 });
// Get terminals
const terminals = await WsfSchedule.getTerminals();
// Get cache flush date
const flushDate = await WsfSchedule.getCacheFlushDate();
```
#### Fares API
```javascript
import { WsfFares } from 'ws-dottie';
// Get fare line items with parameters
const fareItems = await WsfFares.getFareLineItems({
tripDate: new Date('2024-01-15'),
departingTerminalID: 7,
arrivingTerminalID: 8,
roundTrip: false
});
// Get terminals for a date
const terminals = await WsfFares.getTerminals({ tripDate: new Date('2024-01-15') });
// Get valid date range
const dateRange = await WsfFares.getValidDateRange();
```
### WSDOT (Washington State Department of Transportation) APIs
#### Highway Alerts API
```javascript
import { WsdotHighwayAlerts } from 'ws-dottie';
// Get all highway alerts
const alerts = await WsdotHighwayAlerts.getHighwayAlerts();
// Get specific alert by ID
const alert = await WsdotHighwayAlerts.getHighwayAlertById({ alertId: 123 });
```
#### Traffic Flow API
```javascript
import { WsdotTrafficFlow } from 'ws-dottie';
// Get traffic flows
const flows = await WsdotTrafficFlow.getTrafficFlows();
```
#### Travel Times API
```javascript
import { WsdotTravelTimes } from 'ws-dottie';
// Get travel times
const travelTimes = await WsdotTravelTimes.getTravelTimes();
```
#### Toll Rates API
```javascript
import { WsdotTollRates } from 'ws-dottie';
// Get toll rates
const tollRates = await WsdotTollRates.getTollRates();
// Get toll trip info
const tripInfo = await WsdotTollRates.getTollTripInfo();
// Get toll trip rates
const tripRates = await WsdotTollRates.getTollTripRates();
```
#### Weather Information API
```javascript
import { WsdotWeatherInformation } from 'ws-dottie';
// Get weather information for specific stations
const weather = await WsdotWeatherInformation.getWeatherInformationForStations({ stationIds: "1,2,3" });
```
#### Weather Information Extended API
```javascript
import { WsdotWeatherInformationExtended } from 'ws-dottie';
// Get extended weather information
const weather = await WsdotWeatherInformationExtended.getWeatherInformationExtended();
```
#### Weather Stations API
```javascript
import { WsdotWeatherStations } from 'ws-dottie';
// Get weather stations
const stations = await WsdotWeatherStations.getWeatherStations();
```
#### Highway Cameras API
```javascript
import { WsdotHighwayCameras } from 'ws-dottie';
// Get all cameras
const cameras = await WsdotHighwayCameras.getHighwayCameras();
// Get specific camera
const camera = await WsdotHighwayCameras.getCamera({ cameraID: 1001 });
// Search cameras with filters
const searchResults = await WsdotHighwayCameras.searchCameras({
StateRoute: "5",
Region: "Northwest"
});
```
#### Bridge Clearances API
```javascript
import { WsdotBridgeClearances } from 'ws-dottie';
// Get bridge clearances for a route
const clearances = await WsdotBridgeClearances.getBridgeClearances({ route: "005" });
```
#### Mountain Pass Conditions API
```javascript
import { WsdotMountainPassConditions } from 'ws-dottie';
// Get mountain pass conditions
const conditions = await WsdotMountainPassConditions.getMountainPassConditions();
```
#### Commercial Vehicle Restrictions API
```javascript
import { WsdotCommercialVehicleRestrictions } from 'ws-dottie';
// Get commercial vehicle restrictions
const restrictions = await WsdotCommercialVehicleRestrictions.getCommercialVehicleRestrictions();
```
#### Border Crossings API
```javascript
import { WsdotBorderCrossings } from 'ws-dottie';
// Get border crossings
const crossings = await WsdotBorderCrossings.getBorderCrossings();
```
## βοΈ React Hooks
All APIs have corresponding React hooks with built-in caching and TanStack Query integration.
### TanStack Query Setup
WS-Dottie hooks require TanStack Query to be set up in your React application:
```javascript
import { QueryClient, QueryClientProvider } from '/react-query';
import { ReactQueryDevtools } from '/react-query-devtools';
const queryClient = new QueryClient();
function App() {
return (
<QueryClientProvider client={queryClient}>
<TransportationDashboard />
<ReactQueryDevtools />
</QueryClientProvider>
);
}
```
### π― Automatic Type Safety
WS-Dottie hooks provide **automatic type inference** with TanStack Query, eliminating the need for manual type annotations:
```typescript
import { useVesselLocations, useHighwayAlerts } from 'ws-dottie';
function TransportationDashboard() {
// Automatic type inference - no manual typing needed!
const { data: vessels, isLoading, error } = useVesselLocations();
const { data: alerts } = useHighwayAlerts();
// TypeScript automatically knows:
// - vessels: VesselLocation[] | undefined
// - alerts: HighwayAlert[] | undefined
// - isLoading: boolean
// - error: Error | null
return (
<div>
<h2>Vessels: {vessels?.length || 0}</h2>
<h2>Alerts: {alerts?.length || 0}</h2>
{isLoading && <div>Loading...</div>}
</div>
);
}
```
**Key Benefits:**
- **Zero Type Annotations** - No need for `as UseQueryResult<Type, Error>` casting
- **Full IntelliSense** - Complete autocomplete and type checking
- **TanStack Query Integration** - Seamless compatibility with all TanStack Query features
- **Consistent Patterns** - All hooks follow the same type-safe structure
**Type Safety Features:**
- **Automatic Return Type Inference** - All hooks return properly typed `UseQueryResult<T, Error>`
- **Parameter Type Safety** - All hook parameters are fully type-checked
- **Error Type Safety** - Consistent error handling with typed error objects
- **Generic Compatibility** - Works with all TanStack Query options and configurations
### WSF Hooks
```javascript
import {
useVesselLocations,
useVesselVerbose,
useVesselHistoryByVesselAndDateRange,
useMultipleVesselHistories,
useAllVesselHistories,
useVesselStats,
useVesselAccommodations,
useTerminalBasics,
useTerminalWaitTimes,
useTerminalLocations,
useTerminalSailingSpace,
useTerminalTransports,
useTerminalBulletins,
useTerminalVerbose,
useRoutes,
useScheduledRoutes,
useSchedules,
useTerminals,
useFareLineItems,
useFaresTerminals,
useValidDateRange
} from 'ws-dottie';
```
### WSDOT Hooks
```javascript
import {
useHighwayAlerts,
useTrafficFlows,
useTravelTimes,
useTollRates,
useTollTripInfo,
useTollTripRates,
useWeatherInformation,
useWeatherInformationExtended,
useWeatherStations,
useHighwayCameras,
useHighwayCamera,
useSearchCameras,
useBridgeClearances,
useMountainPassConditions,
useCommercialVehicleRestrictions,
useBorderCrossings
} from 'ws-dottie';
```
### Basic Hook Usage
```typescript
import { useVesselLocations, useHighwayAlerts, ApiError } from 'ws-dottie';
function TransportationDashboard() {
// Automatic type inference - TypeScript knows all types automatically
const { data: vessels, isLoading, error } = useVesselLocations();
const { data: alerts } = useHighwayAlerts();
if (error instanceof ApiError) {
return <div>API Error: {error.message}</div>;
}
return (
<div>
<h2>Ferries: {vessels?.length || 0}</h2>
<h2>Highway Alerts: {alerts?.length || 0}</h2>
{isLoading && <div>Loading...</div>}
</div>
);
}
```
### Custom Caching
You can override the default caching behavior with full type safety:
```typescript
import { useVesselLocations } from 'ws-dottie';
function CustomVesselApp() {
// TypeScript automatically infers the correct types even with custom options
const { data: vessels } = useVesselLocations({
staleTime: 5 * 1000, // 5 seconds
refetchInterval: 10 * 1000, // 10 seconds
});
// vessels is still properly typed as VesselLocation[] | undefined
return <div>Vessels: {vessels?.length}</div>;
}
```
### Advanced Caching Customization
WS-Dottie's caching strategies can be customized using spread operators with TanStack Query options:
```typescript
import { useVesselLocations, tanstackQueryOptions } from 'ws-dottie';
function AdvancedVesselTracker() {
// Custom 5-minute update strategy with different parameters
// TypeScript maintains full type safety even with complex configurations
const { data: vessels } = useVesselLocations({
...tanstackQueryOptions.REALTIME_UPDATES, // Start with real-time base
refetchInterval: 5 * 60 * 1000, // 5 minutes
staleTime: 2 * 60 * 1000, // 2 minutes
gcTime: 60 * 60 * 1000, // 1 hour
retry: 3, // 3 retries
retryDelay: 5 * 1000, // 5 second delay between retries
});
return (
<div>
<h2>Vessels (5-minute updates)</h2>
{vessels?.map(vessel => (
<div key={vessel.VesselID}>
<strong>{vessel.VesselName}</strong>
<div>Last Update: {vessel.LastUpdate.toLocaleTimeString()}</div>
</div>
))}
</div>
);
}
```
This approach allows you to:
- **Extend base strategies** - Start with a predefined strategy and customize specific options
- **Mix and match** - Combine different aspects of various strategies
- **Fine-tune performance** - Optimize caching for your specific use case
- **Maintain consistency** - Keep the base strategy's proven defaults while customizing only what you need
### Error Handling in React Components
```typescript
import { useVesselLocations, ApiError } from 'ws-dottie';
function VesselList() {
// TypeScript automatically infers error types for proper error handling
const { data: vessels, isLoading, isFetching, error } = useVesselLocations();
if (isLoading) {
return <div className="loading">Loading vessels...</div>;
}
if (error instanceof ApiError) {
return <div className="error">Error loading vessels: {error.message}</div>;
}
return (
<div>
<h2>Vessels ({vessels?.length || 0})</h2>
{isFetching && <div className="refreshing">Refreshing...</div>}
{vessels?.map(vessel => (
<div key={vessel.VesselID} className="vessel">
<h3>{vessel.VesselName}</h3>
<p>Location: {vessel.Latitude}, {vessel.Longitude}</p>
</div>
))}
</div>
);
}
```
### Overriding Default Options
All hooks use WSβDottieβs `tanstackQueryOptions` presets as sensible defaults. You can override any TanStack Query option perβhook. These are the same options from TanStack Query (`/react-query`), not custom WSβDottie fields:
```typescript
const { data } = useVesselLocations(undefined, { enabled: false }); // disables the query
### Options typing
Hooks accept options typed as `TanStackOptions<TData, TError>`. These map directly to TanStack Queryβs `UseQueryOptions`, but without `queryKey` and `queryFn` (already provided by the hooks).
Note on extra fields: API examples show the core fields for readability. Since WSβDottie uses Zod 4 schemas with passβthrough (`.catchall(z.unknown())`), additional upstream properties may appear and are preserved.
```
## π§ Performance & Caching
WSβDottie provides named TanStack Query presets via `tanstackQueryOptions` (REALTIME_UPDATES, MINUTE_UPDATES, etc.) to give you sensible defaults tuned to each data source. These presets are merged into each hookβs options, and you can supply your own TanStack Query options to override any default at call time. See `tanstackQueryOptions` above for values.
### Caching Strategies by API Type
WS-Dottie provides optimized caching strategies for different data types:
| API Category | Strategy | Stale Time | Refetch Interval | Retries | Use Case |
|--------------|----------|------------|------------------|---------|----------|
| Real-time (Vessels, Alerts) | REALTIME_UPDATES | 5s | 5s | 1 | Live tracking |
| Frequent (Wait Times, Traffic) | MINUTE_UPDATES | 1m | 1m | 0 | Regular updates |
| Static (Terminals, Cameras) | HOURLY_UPDATES | 1h | 1h | 5 | Infrequent changes |
| Historical (Schedules, Fares) | DAILY_UPDATES | 1d | 1d | 5 | Daily updates |
| Static Data (Basics, Verbose) | WEEKLY_UPDATES | 1w | false | 5 | Manual refresh only |
### Caching Configuration
```javascript
import { tanstackQueryOptions } from 'ws-dottie';
// Real-time data (5-second updates)
const realtimeConfig = tanstackQueryOptions.REALTIME_UPDATES;
// Minute updates (1-minute intervals)
const minuteConfig = tanstackQueryOptions.MINUTE_UPDATES;
// Hourly updates (1-hour intervals)
const hourlyConfig = tanstackQueryOptions.HOURLY_UPDATES;
// Daily updates (24-hour intervals)
const dailyConfig = tanstackQueryOptions.DAILY_UPDATES;
// Weekly updates (manual refresh only)
const weeklyConfig = tanstackQueryOptions.WEEKLY_UPDATES;
```
### Configuration Details
| Strategy | Stale Time | GC Time | Refetch Interval | Retry |
|----------|------------|---------|------------------|-------|
| REALTIME_UPDATES | 5s | 1h | 5s | 1 (2s delay) |
| MINUTE_UPDATES | 1m | 1h | 1m | false |
| HOURLY_UPDATES | 1h | 4h | 1h | 5 (30s..2m backoff) |
| DAILY_UPDATES | 1d | 2d | 1d | 5 (1m..10m backoff) |
| WEEKLY_UPDATES | 1w | 2w | false | 5 (1m..10m backoff) |
### Performance Optimization
#### **Caching Strategy**
- **Frequent updates** (5-second stale time, 5-second refetch)
- **Real-time data** with automatic background updates
- **Query deduplication** prevents duplicate API calls
- **Optimized for real-time applications**
#### **Error Recovery**
- **Automatic retry** for network failures
- **Graceful degradation** with user-friendly error messages
- **Cache invalidation** on authentication errors
- **Background refresh** for stale data
#### **Query Deduplication**
WS-Dottie automatically deduplicates identical API calls within the same time window, preventing unnecessary network requests.
#### **Background Refresh**
Data is automatically refreshed in the background when it becomes stale, ensuring users always see fresh data without blocking the UI.
## π― Strong Typing
WS-Dottie provides comprehensive TypeScript types for all APIs, parameters, and responses:
```javascript
import {
WsfVessels,
WsdotHighwayAlerts,
VesselLocation,
HighwayAlert
} from 'ws-dottie';
// All API functions are fully typed
const vessels: VesselLocation[] = await WsfVessels.getVesselLocations();
const alerts: HighwayAlert[] = await WsdotHighwayAlerts.getHighwayAlerts();
// Parameter objects are strongly typed
const camera = await WsdotHighwayCameras.getCamera({ cameraID: 1001 });
const fares = await WsfFares.getFareLineItems({
tripDate: new Date('2024-01-15'),
departingTerminalID: 7,
arrivingTerminalID: 8,
roundTrip: false
});
```
### Type Safety Features
- **Parameter Objects** - All API calls use consistent single-parameter object patterns
- **Response Types** - All API responses are fully typed with TypeScript interfaces
- **Error Types** - Consistent error handling with typed error objects
- **Configuration Types** - Type-safe configuration interface
## π¦ Parameter Object Pattern
All WS-Dottie API functions use a consistent parameter object pattern for better maintainability and type safety:
```javascript
import { WsdotHighwayCameras, WsfFares } from 'ws-dottie';
// Single parameter object for all API calls
const searchResults = await WsdotHighwayCameras.searchCameras({
StateRoute: "5",
Region: "Northwest"
});
const camera = await WsdotHighwayCameras.getCamera({
cameraID: 1001
});
const fares = await WsfFares.getFareLineItems({
tripDate: new Date('2024-01-15'),
departingTerminalID: 7,
arrivingTerminalID: 8,
roundTrip: false
});
```
This pattern provides:
- **Consistency** - All APIs follow the same parameter structure
- **Type Safety** - TypeScript ensures correct parameter types
- **Extensibility** - Easy to add optional parameters without breaking changes
- **Readability** - Clear parameter names and structure
## π¨ Error Handling
All APIs throw `ApiError` for consistent error handling:
```javascript
import { isApiError } from 'ws-dottie';
try {
const data = await WsfVessels.getVesselLocations();
} catch (error) {
if (isApiError(error)) {
console.log('API Error:', error.message);
console.log('Status:', error.status);
console.log('Context:', error.context);
}
}
```
### Error Properties
- `message` - The actual error message from the API or network
- `status` - HTTP status code if available
- `context` - Additional context including endpoint, URL, and timestamp
### Type Guard
Use the `isApiError` type guard for safe error type checking:
```javascript
import { isApiError } from 'ws-dottie';
if (isApiError(error)) {
// TypeScript now knows this is an ApiError
console.log('Status:', error.status);
console.log('Context:', error.context);
}
```
### Error Context
```javascript
import { isApiError } from 'ws-dottie';
if (isApiError(error)) {
console.log('Endpoint:', error.context.endpoint);
console.log('URL:', error.context.url);
console.log('Timestamp:', error.context.timestamp);
console.log('Status:', error.status);
}
```
## π
Data Transformation
WS-Dottie automatically transforms WSDOT/WSF date formats to JavaScript Date objects:
- **`/Date(timestamp)/`** β `Date` object
- **`YYYY-MM-DD`** β `Date` object
- **`MM/DD/YYYY`** β `Date` object
All PascalCase keys are preserved as-is for consistency with WSDOT API.
### Date/Time Properties
WS-Dottie automatically converts WSDOT's .NET date strings to JavaScript Date objects:
```javascript
// WSDOT returns: "/Date(1703123456789)/" β Date
// WSF Schedule returns: "12/25/2024" or "12/25/2024 02:30:45 PM" β Date
const vessel = await WsfVessels.getVesselLocations();
console.log(vessel[0].LastUpdate); // JavaScript Date object
```
### Field Filtering
Responses are pass-through except for date conversion. No fields are stripped; unknown fields are allowed in Zod schemas via `.catchall(z.unknown())`.
### Response Types
All API functions return properly typed data:
```javascript
import { VesselLocation, HighwayAlert } from 'ws-dottie';
const vessels: VesselLocation[] = await WsfVessels.getVesselLocations();
const alerts: HighwayAlert[] = await WsdotHighwayAlerts.getHighwayAlerts();
```
## π Cache Providers
For WSF APIs, you can use cache providers to automatically invalidate data when the server updates:
```javascript
import { VesselCacheProvider, TerminalCacheProvider } from 'ws-dottie';
function App() {
return (
<QueryClientProvider client={queryClient}>
<VesselCacheProvider />
<TerminalCacheProvider />
<MyApp />
</QueryClientProvider>
);
}
```
## π§ͺ Testing
E2E validation and hook tests are provided. See Testing Guide for how to run in Node and simulated browser (JSONP) environments.
## β
API Compliance
### **Real WSDOT API Alignment**
This implementation is **100% compliant** with the official WSDOT APIs:
- **Validated endpoints** with cURL testing
- **Correct data structures** based on actual API responses
- **Proper error handling** for real API scenarios
- **Accurate property names** (PascalCase format)
- **Correct return types** (array of objects for multiple items, single object for specific items)
### **Data Structure Validation**
Based on actual API responses, the implementation correctly handles:
- Array of objects for multiple items
- Single objects for specific items
- Optional location data
- WSDOT date format conversion to JavaScript Date objects
- All required and optional fields
## π Bundle Size
The package is tree-shakeable. Actual bundle impact depends on your imports. Use named imports from `ws-dottie`.
---
**For detailed type definitions, see the TypeScript declarations in your IDE or the source code.**