Package Exports
- ws-dottie
- ws-dottie/apis
- ws-dottie/cli
- ws-dottie/openapi
- ws-dottie/openapi/wsdot-border-crossings.json
- ws-dottie/openapi/wsdot-border-crossings.yaml
- ws-dottie/openapi/wsdot-bridge-clearances.json
- ws-dottie/openapi/wsdot-bridge-clearances.yaml
- ws-dottie/openapi/wsdot-commercial-vehicle-restrictions.json
- ws-dottie/openapi/wsdot-commercial-vehicle-restrictions.yaml
- ws-dottie/openapi/wsdot-highway-alerts.json
- ws-dottie/openapi/wsdot-highway-alerts.yaml
- ws-dottie/openapi/wsdot-highway-cameras.json
- ws-dottie/openapi/wsdot-highway-cameras.yaml
- ws-dottie/openapi/wsdot-mountain-pass-conditions.json
- ws-dottie/openapi/wsdot-mountain-pass-conditions.yaml
- ws-dottie/openapi/wsdot-toll-rates.json
- ws-dottie/openapi/wsdot-toll-rates.yaml
- ws-dottie/openapi/wsdot-traffic-flow.json
- ws-dottie/openapi/wsdot-traffic-flow.yaml
- ws-dottie/openapi/wsdot-travel-times.json
- ws-dottie/openapi/wsdot-travel-times.yaml
- ws-dottie/openapi/wsdot-weather-information.json
- ws-dottie/openapi/wsdot-weather-information.yaml
- ws-dottie/openapi/wsdot-weather-readings.json
- ws-dottie/openapi/wsdot-weather-readings.yaml
- ws-dottie/openapi/wsdot-weather-stations.json
- ws-dottie/openapi/wsdot-weather-stations.yaml
- ws-dottie/openapi/wsf-fares.json
- ws-dottie/openapi/wsf-fares.yaml
- ws-dottie/openapi/wsf-schedule.json
- ws-dottie/openapi/wsf-schedule.yaml
- ws-dottie/openapi/wsf-terminals.json
- ws-dottie/openapi/wsf-terminals.yaml
- ws-dottie/openapi/wsf-vessels.json
- ws-dottie/openapi/wsf-vessels.yaml
- ws-dottie/src
- ws-dottie/types
- ws-dottie/wsdot-border-crossings
- ws-dottie/wsdot-border-crossings/core
- ws-dottie/wsdot-border-crossings/schemas
- ws-dottie/wsdot-bridge-clearances
- ws-dottie/wsdot-bridge-clearances/core
- ws-dottie/wsdot-bridge-clearances/schemas
- ws-dottie/wsdot-commercial-vehicle-restrictions
- ws-dottie/wsdot-commercial-vehicle-restrictions/core
- ws-dottie/wsdot-commercial-vehicle-restrictions/schemas
- ws-dottie/wsdot-highway-alerts
- ws-dottie/wsdot-highway-alerts/core
- ws-dottie/wsdot-highway-alerts/schemas
- ws-dottie/wsdot-highway-cameras
- ws-dottie/wsdot-highway-cameras/core
- ws-dottie/wsdot-highway-cameras/schemas
- ws-dottie/wsdot-mountain-pass-conditions
- ws-dottie/wsdot-mountain-pass-conditions/core
- ws-dottie/wsdot-mountain-pass-conditions/schemas
- ws-dottie/wsdot-toll-rates
- ws-dottie/wsdot-toll-rates/core
- ws-dottie/wsdot-toll-rates/schemas
- ws-dottie/wsdot-traffic-flow
- ws-dottie/wsdot-traffic-flow/core
- ws-dottie/wsdot-traffic-flow/schemas
- ws-dottie/wsdot-travel-times
- ws-dottie/wsdot-travel-times/core
- ws-dottie/wsdot-travel-times/schemas
- ws-dottie/wsdot-weather-information
- ws-dottie/wsdot-weather-information/core
- ws-dottie/wsdot-weather-information/schemas
- ws-dottie/wsdot-weather-readings
- ws-dottie/wsdot-weather-readings/core
- ws-dottie/wsdot-weather-readings/schemas
- ws-dottie/wsdot-weather-stations
- ws-dottie/wsdot-weather-stations/core
- ws-dottie/wsdot-weather-stations/schemas
- ws-dottie/wsf-fares
- ws-dottie/wsf-fares/core
- ws-dottie/wsf-fares/schemas
- ws-dottie/wsf-schedule
- ws-dottie/wsf-schedule/core
- ws-dottie/wsf-schedule/schemas
- ws-dottie/wsf-terminals
- ws-dottie/wsf-terminals/core
- ws-dottie/wsf-terminals/schemas
- ws-dottie/wsf-vessels
- ws-dottie/wsf-vessels/core
- ws-dottie/wsf-vessels/schemas
Readme
WS-Dottie ๐ข
Table of Contents
- Why WS-Dottie is Special
- Zod-powered validation
- What You Can Build
- Quick Start
- Command Line Interface
- Available Data Sources
- Core Features
- Production vs Development
- TanStack Query Integration
- Documentation
- Implementation Examples
- Example Projects
- Testing
- Governance
- Contributing
- License
Meet Dottie โ your comprehensive TypeScript companion for fetching real-time Washington State transportation data. This production-ready library provides type-safe access to 16 WSDOT and WSF APIs with 98 endpoints, transforming complex government APIs into a modern, developer-friendly interface.
Why WS-Dottie is Special
๐ Comprehensive Coverage: Access full spectrum of Washington State transportation data โ from real-time ferry locations and traffic cameras to weather stations, highway alerts, toll rates, and border crossings.
๐ฏ Production-Ready: Built for real applications with smart caching strategies, comprehensive error handling, and environment-aware logging. Works seamlessly in browsers (JSONP), servers (native fetch), and CLI environments.c
โก Developer Experience: Type-safe from end-to-end with Zod validation, automatic .NET datetime conversion, and sensible defaults. Includes a powerful CLI for debugging and testing.
๐ Smart Caching: TanStack Query integration with transportation-optimized cache strategies โ from 5-second real-time updates for traffic cameras to daily updates for static data like terminals and vessels.
๐ Environment Agnostic: Same code works in React apps, Node.js servers, and command-line tools. Automatic CORS handling with JSONP support for browsers.
Zodโpowered validation (Zod 3)
WSโDottie uses Zod 3 schemas for optional runtime validation and type inference across all APIs. Validation is disabled by default (validate: false) for optimal performance, but you can enable it when you need extra safety.
- With validation (
validate: true): Strong runtime type safety, early detection of API changes, and safe data transformations - Without validation (
validate: false- default): Faster performance, smaller bundles, and still type-safe with TypeScript
For detailed information about validation, performance trade-offs, and best practices, see the Validation Guide.
โจ What You Can Build
- ๐ข Ferry Tracking Apps - Real-time vessel locations, terminal wait times, and sailing schedules
- ๐ Traffic Monitoring Dashboards - Live traffic flow, travel times, and highway alerts
- ๐ค๏ธ Weather & Road Condition Apps - Weather station data and mountain pass conditions
- ๐ท Camera Feeds - Access to hundreds of traffic cameras across Washington
- ๐ฐ Toll Rate Calculators - Real-time toll pricing for planning trips
- ๐ Commercial Vehicle Tools - Bridge clearances and vehicle restrictions
- ๐ Border Crossing Apps - Wait times and conditions at border crossings
๐ Quick Start
1. Get Your Free API Key
Visit WSDOT Developer Portal and sign up with just your email address. No credit card required โ API is completely free.
2. Install WS-Dottie
npm install ws-dottie3. Configure Your API Key
Option A: Environment Variables (Recommended)
# For Node.js applications
export WSDOT_ACCESS_TOKEN=your_api_key_hereUsing a .env file
WSDOT_ACCESS_TOKEN=your_api_key_hereOption B: Runtime Configuration
For dynamic environments or when you need to configure at runtime:
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');4. Module Format Support
WSโDottie supports both CommonJS and ES Module formats:
ES Modules (Recommended)
import { configManager, fetchDottie } from 'ws-dottie';
import { useVesselLocations } from 'ws-dottie/wsf-vessels';
import { useAlerts } from 'ws-dottie/wsdot-highway-alerts';CommonJS
const { configManager, fetchDottie } = require('ws-dottie');
const { useVesselLocations } = require('ws-dottie/wsf-vessels');
const { useAlerts } = require('ws-dottie/wsdot-highway-alerts');Modern bundlers and Node.js will choose the optimal format automatically.
5. Import Patterns
WS-Dottie provides multiple import patterns optimized for different use cases. Choose the pattern that best fits your needs:
Shared Utilities (Main Entry)
The root package now exposes shared utilities only:
import { configManager, fetchDottie, datesHelper } from 'ws-dottie';
import type { ApiError } from 'ws-dottie';Use when: You need global configuration, low-level fetching, or shared helpers.
API Hooks and Types
Import hooks, fetch functions, and types for a specific API from its package entry:
import { useVesselLocations, type VesselLocation } from 'ws-dottie/wsf-vessels';
import { useAlerts, type Alert } from 'ws-dottie/wsdot-highway-alerts';Use when: You want React hooks and types for a particular API.
Core Fetch Functions (No Hooks)
Import only fetch functions and types โ no React dependencies:
import {
fetchVesselLocations, // Fetch functions only
type VesselLocation // TypeScript types
} from 'ws-dottie/wsf-vessels/core';Use when: Building server-side code, Node.js scripts, or when you don't need React hooks. Excludes TanStack Query dependencies for smaller bundles.
Schema Imports (Zod Schemas Only)
Import Zod schemas for custom validation or type inference:
import {
vesselLocationsSchema, // Zod schema
type VesselLocation // Inferred TypeScript type
} from 'ws-dottie/wsf-vessels/schemas';Use when: You need Zod schemas for custom validation logic or want to build your own validation layer.
TypeScript Types
WS-Dottie exports TypeScript types for all API inputs and outputs. Types are available from the same import paths as functions:
Importing Types:
// Import types along with functions
import {
fetchVesselLocations,
type VesselLocation, // Output type (single item)
type VesselLocationsInput, // Input type
} from 'ws-dottie/wsf-vessels/core';
// Import types without functions
import type { VesselLocation } from 'ws-dottie/wsf-vessels/schemas';Using Types in Your Code:
import {
fetchVesselLocations,
type VesselLocation,
} from 'ws-dottie/wsf-vessels/core';
// Type function parameters
async function processVessel(vessel: VesselLocation) {
console.log(`Processing ${vessel.VesselName}`);
}
// Type function return values
async function getVesselData(): Promise<VesselLocation[]> {
const vessels = await fetchVesselLocations({
fetchMode: 'native',
validate: false
});
return vessels;
}
// Type variables
const vessel: VesselLocation = {
VesselID: 18,
VesselName: 'Chelan',
// ... other properties
};Input vs Output Types:
- Input types (
*Input): Parameters for API functions- Example:
VesselLocationsByIdInputforfetchVesselLocationsByVesselId
- Example:
- Output types: Response data from API functions
- Example:
VesselLocation(single item) orVesselLocation[](array)
- Example:
Types with React Hooks:
import {
useVesselLocations,
type VesselLocation
} from 'ws-dottie/wsf-vessels';
function VesselList() {
const { data: vessels } = useVesselLocations({
fetchMode: 'native',
validate: false,
});
// TypeScript knows vessels is VesselLocation[] | undefined
if (!vessels) return <div>Loading...</div>;
return (
<ul>
{vessels.map((vessel: VesselLocation) => (
<li key={vessel.VesselID}>{vessel.VesselName}</li>
))}
</ul>
);
}Type Naming Convention:
- Output types: PascalCase singular (e.g.,
VesselLocation,HighwayAlert) - Input types: PascalCase with
Inputsuffix (e.g.,VesselLocationsInput,VesselLocationsByIdInput) - Arrays: Use TypeScript array syntax (e.g.,
VesselLocation[])
6. Start Building
React Application (Recommended)
import { useVesselLocations } from 'ws-dottie/wsf-vessels';
import { useAlerts } from 'ws-dottie/wsdot-highway-alerts';
function TransportationDashboard() {
const { data: vessels, isLoading } = useVesselLocations({
fetchMode: 'native',
validate: false,
});
const { data: alerts } = useAlerts({
fetchMode: 'native',
validate: true,
});
return (
<div>
<h2>Active Ferries: {vessels?.length || 0}</h2>
<h2>Highway Alerts: {alerts?.length || 0}</h2>
{isLoading && <div>Loading...</div>}
</div>
);
}Server-Side (Node.js)
import {
fetchVesselLocationsByVesselId,
fetchFareLineItemsByTripDateAndTerminals,
} from 'ws-dottie/wsf-vessels/core';
import { fetchAlertById } from 'ws-dottie/wsdot-highway-alerts/core';
import { fetchBorderCrossings } from 'ws-dottie/wsdot-border-crossings/core';
// Get specific vessel location (VesselID: 18)
const vessel = await fetchVesselLocationsByVesselId({
params: { VesselID: 18 },
fetchMode: 'native',
validate: true,
});
// Get specific highway alert (AlertID: 468632)
const alert = await fetchAlertById({
params: { AlertID: 468632 },
fetchMode: 'native',
validate: true,
});
// Get ferry fare information for tomorrow's trip
const fares = await fetchFareLineItemsByTripDateAndTerminals({
params: {
TripDate: '2025-01-28',
DepartingTerminalID: 3,
ArrivingTerminalID: 7,
RoundTrip: false,
},
fetchMode: 'native',
validate: true,
});
// Get all border crossings
const crossings = await fetchBorderCrossings({
fetchMode: 'native',
validate: true,
});Browser (CORS-Safe)
import { fetchVesselBasicsByVesselId } from 'ws-dottie/wsf-vessels/core';
import { fetchBridgeClearancesByRoute } from 'ws-dottie/wsdot-bridge-clearances/core';
// Get specific vessel details (VesselID: 74)
const vessel = await fetchVesselBasicsByVesselId({
params: { VesselID: 74 },
fetchMode: 'jsonp', // Bypasses CORS
validate: true
});
// Get bridge clearances for I-5 (Route: "005")
const clearances = await fetchBridgeClearancesByRoute({
params: { Route: "005" },
fetchMode: 'jsonp',
validate: true
});Command Line (Debugging & Testing)
# List all available endpoints
fetch-dottie --list
# Test specific vessel location (VesselID: 18)
fetch-dottie fetchVesselLocationsByVesselId '{"VesselID": 18}'
# Get ferry fares for specific trip
fetch-dottie fetchFareLineItemsByTripDateAndTerminals '{"TripDate": "2025-01-28", "DepartingTerminalID": 3, "ArrivingTerminalID": 7, "RoundTrip": false}'
# Fast testing without validation (raw data)
fetch-dottie fetchVesselBasicsByVesselId '{"VesselID": 74}' --no-validation --pretty
# Browser-compatible JSONP testing with parameters
fetch-dottie fetchBridgeClearancesByRoute '{"Route": "005"}' --jsonp๐ OpenAPI JSON Exports
WS-Dottie exports OpenAPI 3.0 specifications for all APIs as JSON files, making them easily consumable by other tools and services like ws-dottie-mcp. These exports provide a complete machine-readable description of all endpoints, schemas, and documentation.
Importing OpenAPI Specifications
You can import OpenAPI specifications directly from the ws-dottie package:
// Import a specific API specification
import wsfVesselsSpec from 'ws-dottie/openapi/wsf-vessels.json' assert { type: 'json' };
// Use the specification in your application
console.log(`API Title: ${wsfVesselsSpec.info.title}`);
console.log(`Available endpoints: ${Object.keys(wsfVesselsSpec.paths).length}`);Available API Specifications
All 16 APIs have OpenAPI specifications available:
Washington State Ferries (WSF) APIs:
wsf-vessels.json- Vessel locations, stats, and informationwsf-terminals.json- Terminal locations and informationwsf-schedule.json- Sailing schedules and routeswsf-fares.json- Fare information and pricing
Washington State Department of Transportation (WSDOT) APIs:
wsdot-border-crossings.json- Border crossing wait timeswsdot-bridge-clearances.json- Bridge clearance informationwsdot-commercial-vehicle-restrictions.json- Commercial vehicle restrictionswsdot-highway-alerts.json- Highway alerts and incidentswsdot-highway-cameras.json- Highway camera imageswsdot-mountain-pass-conditions.json- Mountain pass conditionswsdot-toll-rates.json- Toll rate informationwsdot-traffic-flow.json- Traffic flow datawsdot-travel-times.json- Travel time estimateswsdot-weather-information.json- Weather informationwsdot-weather-readings.json- Weather sensor readingswsdot-weather-stations.json- Weather station locations
Using with External Tools
The OpenAPI JSON exports are particularly useful when integrating with:
- API documentation tools - Generate documentation sites
- Code generation tools - Create client libraries
- Testing frameworks - Automated API testing
- API gateways - Proxy and route APIs
- MCP servers - Expose APIs through Model Context Protocol
Example with ws-dottie-mcp
// In ws-dottie-mcp configuration
import wsfVesselsSpec from 'ws-dottie/openapi/wsf-vessels.json' assert { type: 'json' };
// Use the specification to configure MCP server
const mcpServer = new MCPServer({
name: 'wsf-vessels',
openapiSpec: wsfVesselsSpec
});๐ API Graph
WS-Dottie exports a centralized API graph that serves as the single source of truth for all endpoint definitions. The graph provides structured access to API metadata, endpoint groups, and endpoint configurations, enabling programmatic introspection of available endpoints and their properties.
The API graph is available through the ./apis package export and contains metadata for all 16 APIs, their endpoint groups, and individual endpoints with their schemas, cache strategies, and documentation. This makes it ideal for building tools that need to discover endpoints dynamically, generate documentation, or create custom integrations.
import { apis } from 'ws-dottie/apis';
// Access a specific API
const vesselsApi = apis['wsf-vessels'];
// Iterate through endpoint groups
vesselsApi.endpointGroups.forEach(group => {
console.log(`Group: ${group.name}, Strategy: ${group.cacheStrategy}`);
// Access endpoints in each group
group.endpoints.forEach(endpoint => {
console.log(` Endpoint: ${endpoint.functionName}`);
console.log(` Path: ${endpoint.endpoint}`);
});
});
// Get all endpoints across all APIs
const allEndpoints = Object.values(apis).flatMap(api =>
api.endpointGroups.flatMap(group => group.endpoints)
);Endpoint Registry
WS-Dottie also exports a centralized endpoint registry that provides two complementary views of all endpoints:
endpointsFlat - A flat array of all endpoints, ideal for iteration and searching:
import { endpointsFlat } from 'ws-dottie/apis';
// Find an endpoint by function name
const endpoint = endpointsFlat.find(ep => ep.functionName === 'vesselBasics');
// Filter by API
const wsfEndpoints = endpointsFlat.filter(ep => ep.api.name.startsWith('wsf-'));endpointsByApi - A nested structure organized by API โ Group โ Function, useful for direct hierarchical access:
import { endpointsByApi } from 'ws-dottie/apis';
// Direct access to a specific endpoint
const vesselEndpoint = endpointsByApi['wsf-vessels']['vesselBasics']['vesselBasics'];The registry is automatically generated from the API graph and includes complete endpoint metadata (schemas, cache strategies, URLs, etc.). It's used internally by the CLI, E2E tests, and documentation generation tools.
๐ฅ๏ธ Command Line Interface
WS-Dottie includes a comprehensive CLI tool (fetch-dottie) that provides production-ready debugging and testing capabilities. Access all 98 endpoints directly from your terminal with configurable transport strategies and validation options.
Installation
The CLI is included with WS-Dottie and works in Node.js environments:
# Install ws-dottie (includes CLI)
npm install ws-dottie
# Or use directly with npx (no installation required)
npx fetch-dottie --helpConfiguration
Set your WSDOT API key as an environment variable:
export WSDOT_ACCESS_TOKEN=your_api_key_hereUsage
fetch-dottie <function-name> [params] [options]Examples
๐ Quick Testing & Debugging
# List all available endpoints
fetch-dottie --list
# Test any endpoint with full validation
fetch-dottie fetchBorderCrossings
# Fast testing without validation (raw data)
fetch-dottie fetchVesselBasics --no-validation๐ Environment Testing
# Server-side testing (default)
fetch-dottie fetchVesselLocations
# Browser environment testing (JSONP)
fetch-dottie fetchBorderCrossings --jsonp
# Mixed: JSONP without validation (fastest)
fetch-dottie fetchVesselBasics --jsonp --no-validation๐ Data Exploration
# Get bridge clearances for I-5
fetch-dottie fetchBridgeClearancesByRoute '{"Route": "005"}'
# Get ferry fare information for specific trip
fetch-dottie fetchFareLineItemsByTripDateAndTerminals '{"TripDate": "2025-01-28", "DepartingTerminalID": 3, "ArrivingTerminalID": 7, "RoundTrip": false}'
# Get specific vessel location (VesselID: 18)
fetch-dottie fetchVesselLocationsByVesselId '{"VesselID": 18}'
# Get specific highway alert (AlertID: 468632)
fetch-dottie fetchAlertById '{"AlertID": 468632}'
# Get weather from specific station (StationID: 1909)
fetch-dottie fetchWeatherInformationByStationId '{"StationID": 1909}'
# Get vessel history for specific date range
fetch-dottie fetchVesselHistoriesByVesselNameAndDateRange '{"VesselName": "Tacoma", "DateStart": "2025-09-01", "DateEnd": "2025-10-01"}'
# Pretty-printed output
fetch-dottie fetchBorderCrossings --pretty
# Concise array output
fetch-dottie fetchVesselLocations --concise
# Silent mode (JSON only)
fetch-dottie fetchBorderCrossings --silent
# Limit output to first 5 items
fetch-dottie fetchVesselLocations --limit 5Available Functions
The CLI supports all 98 endpoints across 16 APIs:
- WSDOT APIs: Border Crossings, Bridge Clearances, Highway Alerts, Traffic Cameras, Weather Stations, Travel Times, Toll Rates, Mountain Passes, Commercial Vehicle Restrictions
- WSF APIs: Ferry Schedules, Vessel Locations, Terminal Information, Fare Data
Use fetch-dottie --help to see all available functions with descriptions.
CLI Options
Transport & Validation Control
--jsonp- Use JSONP transport for browser environments (bypasses CORS)--no-validation- Disable Zod validation (raw fetch with .NET date conversion)
Output Formatting
--pretty- Pretty-print JSON output with 2-space indentation (default)--concise- Concise array output with brackets on own lines--silent- Suppress all output except final JSON result--limit <number>- Truncate output to first N items
Discovery
--list- List all available endpoints with descriptions
๐ Available Data Sources (16 APIs, 98 endpoints)
WSDOT APIs
- Highway Alerts - Real-time traffic incidents and construction updates
- Traffic Flow - Current traffic speeds and congestion data
- Travel Times - Estimated travel times between locations
- Toll Rates - Real-time toll pricing for managed lanes
- Weather Information - Road weather conditions and forecasts
- Highway Cameras - Live traffic camera feeds across state
- Bridge Clearances - Height restrictions for commercial vehicles
- Mountain Pass Conditions - Pass status and travel restrictions
- Commercial Vehicle Restrictions - Truck and commercial vehicle limits
- Border Crossings - Wait times and conditions at border crossings
- Weather Stations - Weather station data and road conditions
WSF APIs
- Vessels - Real-time vessel locations and status
- Terminals - Terminal wait times and sailing space
- Schedules - Ferry schedules and sailing times
- Fares - Fare information and pricing
๐ง Core Features
๐ Comprehensive API Coverage
- 16 distinct APIs covering WSDOT (traffic, weather, tolls) and WSF (ferries, schedules)
- 98 endpoints with full type safety and validation
- Unified interface โ all APIs work consistently regardless of source
๐ Smart Caching & React Integration
- TanStack Query integration with transportation-optimized cache strategies:
REALTIME(5-second updates) for traffic cameras, vessel locationsFREQUENT(5-minute updates) for schedules, alertsMODERATE(hourly updates) for weather, conditionsSTATIC(daily updates) for terminals, vessels, routes
- Zero-configuration React hooks with automatic revalidation and background refresh
- Hooks Factory: Automatically generates TanStack Query hooks for all API endpoints with proper caching strategies
๐ Flexible Fetching Strategies
- Native fetch for server-side and Node.js applications
- JSONP support for browser environments (bypasses CORS restrictions)
- Optional Zod validation for performance vs. safety tradeoffs (disabled by default)
- Unified API โ same code works in browser and server
๐ ๏ธ Production-Ready Developer Experience
- Command-line debugging tool with all endpoints accessible via CLI
- Comprehensive error handling with detailed context and helpful messages
- Environment-aware logging with performance metrics
- Automatic .NET datetime conversion (handles WSDOT's
/Date(timestamp)/format) - Type-safe configuration via environment variables or runtime setup
- Documentation generation with OpenAPI specs and interactive HTML docs
๐ Automated Documentation
- OpenAPI Specification Generation: Automatically generates OpenAPI 3.1 specifications from Zod schemas
- Interactive HTML Documentation: Redoc-powered documentation with examples and schema exploration
- Sample Data Management: Fetches and maintains real API response samples for documentation
- Documentation Scripts:
npm run docs:generatecreates complete documentation from source code
๐ฏ Developer-Friendly Design
- Strong TypeScript types inferred from Zod schemas
- Consistent parameter patterns across all APIs
- Tree-shaking support โ only import what you need
- Sample parameters provided for every endpoint
๐ฏ Production vs Development
When to Use Validation
Use validation (validate: true) in production when:
- You need to catch API response changes early
- Data integrity is critical for your application
- You want runtime type safety beyond TypeScript
- You're integrating with third-party APIs that may change
Skip validation (validate: false) in production when:
- Performance is critical and API is stable
- Bundle size matters (validation adds ~50-100KB)
- You trust the API provider's stability
- You're making many rapid API calls
Development vs Production Patterns
// Development: Use validation to catch issues early
const vessels = await fetchVesselLocations({
fetchMode: 'native',
validate: process.env.NODE_ENV === 'development'
});
// Production: Optimize for performance
const vessels = await fetchVesselLocations({
fetchMode: 'native',
validate: false // Faster, smaller bundle
});
// Conditional: Best of both worlds
const vessels = await fetchVesselLocations({
fetchMode: 'native',
validate: process.env.NODE_ENV !== 'production'
});Bundle Size Optimization
- Full build with validation: ~200-300KB (includes Zod schemas)
- Light build without validation: ~100-150KB (schemas tree-shaken out)
- API-specific imports: Further reduces bundle size by excluding unused APIs
- Core-only imports: Excludes React/TanStack Query (~50KB savings)
Use API-specific or core-only imports for optimal tree-shaking:
// Smaller bundle - only includes wsf-vessels API
import { fetchVesselLocations } from 'ws-dottie/wsf-vessels/core';
// Even smaller - no React hooks
import { fetchVesselLocations } from 'ws-dottie/wsf-vessels/core';๐ TanStack Query Integration
WS-Dottie provides zero-configuration React hooks with transportation-optimized caching strategies. Each API endpoint automatically uses the appropriate cache strategy based on data update frequency.
Every hook now accepts the same FetchFunctionParams<T> object as its corresponding fetch function. Pass endpoint parameters with params, override fetching behavior with fetchMode, and toggle validation with validateโthen optionally provide TanStack Query options as the second argument.
Cache Strategies
import {
useVesselLocations,
useVesselBasics,
} from 'ws-dottie/wsf-vessels';
import { useAlerts } from 'ws-dottie/wsdot-highway-alerts';
function TransportationDashboard() {
// REALTIME: 5-second updates for vessel locations
const { data: vessels, isLoading: vesselsLoading } = useVesselLocations({
fetchMode: 'native',
validate: false,
});
// FREQUENT: 5-minute updates for highway alerts
const { data: alerts, isLoading: alertsLoading } = useAlerts({
fetchMode: 'native',
validate: true,
});
// STATIC: Daily updates for vessel information
const { data: vesselInfo } = useVesselBasics({
fetchMode: 'native',
validate: true,
});
return (
<div>
<h2>Active Vessels: {vessels?.length || 0}</h2>
<h2>Highway Alerts: {alerts?.length || 0}</h2>
<h2>Vessel Details: {vesselInfo?.length || 0}</h2>
</div>
);
}Parameterized Queries
import { useVesselLocationsByVesselId } from 'ws-dottie/wsf-vessels';
import { useAlertById } from 'ws-dottie/wsdot-highway-alerts';
import { useFareLineItemsByTripDateAndTerminals } from 'ws-dottie/wsf-fares';
function SpecificDataView() {
// Get specific vessel location (REALTIME caching)
const { data: vessel } = useVesselLocationsByVesselId({
params: { VesselID: 18 },
fetchMode: 'native',
validate: true,
});
// Get specific highway alert (FREQUENT caching)
const { data: alert } = useAlertById({
params: { AlertID: 468632 },
fetchMode: 'native',
validate: true,
});
// Get ferry fares for specific trip (STATIC caching)
const { data: fares } = useFareLineItemsByTripDateAndTerminals({
params: {
TripDate: '2025-01-28',
DepartingTerminalID: 3,
ArrivingTerminalID: 7,
RoundTrip: false
},
fetchMode: 'native',
validate: true,
});
return (
<div>
<h3>Vessel: {vessel?.VesselName}</h3>
<h3>Alert: {alert?.Headline}</h3>
<h3>Fares: {fares?.length} options</h3>
</div>
);
}Advanced Query Options
import { useQuery } from '@tanstack/react-query';
import { fetchVesselBasicsByVesselId } from 'ws-dottie/wsf-vessels/core';
function CustomQueryExample() {
const { data, error, isLoading } = useQuery({
queryKey: ['vessel', 74],
queryFn: () => fetchVesselBasicsByVesselId({
params: { VesselID: 74 },
fetchMode: 'native',
validate: true
}),
staleTime: 60 * 1000, // Custom stale time
refetchInterval: 30 * 1000, // Custom refetch interval
retry: 3,
retryDelay: 1000
});
if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return <div>Vessel: {data?.VesselName}</div>;
}Cache Strategy Details
|| Strategy | Update Frequency | Use Cases | Stale Time | Refetch Interval |
||----------|------------------|-----------|------------|------------------|
|| REALTIME | 5 seconds | Traffic cameras, vessel locations | 5s | 5s |
|| FREQUENT | 5 minutes | Schedules, alerts, weather | 5m | 5m |
|| MODERATE | 1 hour | Weather conditions, road status | 1h | 1h |
|| STATIC | 1 day | Terminals, vessels, routes | 1d | 1d |
๐ Quick Reference
Common Import Patterns
// React hooks (recommended for UI)
import { useVesselLocations } from 'ws-dottie/wsf-vessels';
import { useAlerts } from 'ws-dottie/wsdot-highway-alerts';
// Server-side functions (no React)
import { fetchVesselLocations } from 'ws-dottie/wsf-vessels/core';
import { fetchAlerts } from 'ws-dottie/wsdot-highway-alerts/core';
// TypeScript types only
import type { VesselLocation } from 'ws-dottie/wsf-vessels';Basic Usage Examples
// Get all vessel locations
const { data: vessels } = useVesselLocations({
fetchMode: 'native',
validate: false
});
// Get specific vessel by ID
const { data: vessel } = useVesselLocationsByVesselId({
params: { VesselID: 18 },
fetchMode: 'native',
validate: true
});
// Get highway alerts for a region
const { data: alerts } = useAlertsByRegionId({
params: { RegionID: 9 },
fetchMode: 'jsonp', // For browser
validate: true
});Configuration Options
// Set API key
import { configManager } from 'ws-dottie';
configManager.setApiKey('your_api_key_here');
// Environment variable
export WSDOT_ACCESS_TOKEN=your_api_key_hereCLI Commands
# List all endpoints
fetch-dottie --list
# Get vessel locations
fetch-dottie fetchVesselLocations
# Get specific vessel with pretty output
fetch-dottie fetchVesselLocationsByVesselId '{"VesselID": 18}' --pretty๐ Documentation
- Documentation Home - Complete documentation index with getting started guides and API reference
- Getting Started - New to WS-Dottie? Start here
- API Guide - High-level API overview and use cases
- Interactive Documentation - Browse APIs with live examples
๐ Detailed API Documentation
For detailed endpoint documentation, interactive examples, and schema definitions, see our generated documentation:
- OpenAPI Specifications - API specifications in JSON format
- OpenAPI Specifications (YAML) - API specifications in YAML format
- HTML Documentation - Interactive HTML documentation with examples
Our documentation is automatically generated from API definitions, ensuring it stays synchronized with the latest code changes.
๐ฏ Implementation Examples
React Dashboard (Recommended)
import {
useVesselLocations,
useVesselLocationsByVesselId,
} from 'ws-dottie/wsf-vessels';
import {
useAlerts,
useAlertById,
} from 'ws-dottie/wsdot-highway-alerts';
import { useFareLineItemsByTripDateAndTerminals } from 'ws-dottie/wsf-fares';
function TransportationDashboard() {
// Real-time data with automatic caching
const { data: allVessels, isLoading: vesselsLoading } = useVesselLocations({
fetchMode: 'native',
validate: false,
});
const { data: alerts, isLoading: alertsLoading } = useAlerts({
fetchMode: 'native',
validate: true,
});
// Specific vessel tracking (VesselID: 18)
const { data: specificVessel } = useVesselLocationsByVesselId({
params: { VesselID: 18 },
fetchMode: 'native',
validate: true,
});
// Specific alert details (AlertID: 468632)
const { data: alertDetails } = useAlertById({
params: { AlertID: 468632 },
fetchMode: 'native',
validate: true,
});
// Ferry fare calculation for tomorrow's trip
const { data: fares } = useFareLineItemsByTripDateAndTerminals({
params: {
TripDate: '2025-01-28',
DepartingTerminalID: 3,
ArrivingTerminalID: 7,
RoundTrip: false,
},
fetchMode: 'native',
validate: true,
});
return (
<div className="dashboard">
<section>
<h2>Active Ferries: {allVessels?.length || 0}</h2>
{specificVessel && <p>Tracking: {specificVessel.VesselName}</p>}
{vesselsLoading && <div>Loading vessels...</div>}
</section>
<section>
<h2>Highway Alerts: {alerts?.length || 0}</h2>
{alertDetails && <p>Latest: {alertDetails.Headline}</p>}
{alertsLoading && <div>Loading alerts...</div>}
</section>
<section>
<h2>Trip Planning</h2>
<p>Ferry fares: {fares?.length || 0} options available</p>
</section>
</div>
);
}Server-Side API Integration
import { fetchBorderCrossings } from 'ws-dottie/wsdot-border-crossings/core';
import { fetchVesselLocationsByVesselId } from 'ws-dottie/wsf-vessels/core';
import { fetchAlertById } from 'ws-dottie/wsdot-highway-alerts/core';
import { fetchBridgeClearancesByRoute } from 'ws-dottie/wsdot-bridge-clearances/core';
// Express.js route handler with parameterized queries
app.get('/api/transportation/:vesselId/:alertId', async (req, res) => {
try {
const { vesselId, alertId } = req.params;
const [crossings, vessel, alert, clearances] = await Promise.all([
// All border crossings
fetchBorderCrossings({
fetchMode: 'native',
validate: true
}),
// Specific vessel location
fetchVesselLocationsByVesselId({
params: { VesselID: parseInt(vesselId) },
fetchMode: 'native',
validate: true
}),
// Specific highway alert
fetchAlertById({
params: { AlertID: parseInt(alertId) },
fetchMode: 'native',
validate: true
}),
// Bridge clearances for I-5
fetchBridgeClearancesByRoute({
params: { Route: "005" },
fetchMode: 'native',
validate: true
})
]);
res.json({ crossings, vessel, alert, clearances });
} catch (error) {
res.status(500).json({ error: error.message });
}
});Browser Application (CORS-Safe)
import { fetchVesselBasicsByVesselId } from 'ws-dottie/wsf-vessels/core';
import { fetchWeatherInformationByStationId } from 'ws-dottie/wsdot-weather-information/core';
import { fetchAlertsByRegionId } from 'ws-dottie/wsdot-highway-alerts/core';
// Browser-safe data fetching with parameters
async function loadTransportationData(vesselId = 74, stationId = 1909, regionId = 9) {
const [vessel, weather, regionalAlerts] = await Promise.all([
// Specific vessel details
fetchVesselBasicsByVesselId({
params: { VesselID: vesselId },
fetchMode: 'jsonp', // Bypasses CORS
validate: true
}),
// Weather from specific station
fetchWeatherInformationByStationId({
params: { StationID: stationId },
fetchMode: 'jsonp',
validate: true
}),
// Alerts from specific region
fetchAlertsByRegionId({
params: { RegionID: regionId },
fetchMode: 'jsonp',
validate: true
})
]);
return { vessel, weather, regionalAlerts };
}CLI Automation & Testing
#!/bin/bash
# Automated monitoring script with specific parameters
# Check specific vessel status (VesselID: 18)
echo "=== Vessel Status ==="
fetch-dottie fetchVesselLocationsByVesselId '{"VesselID": 18}' --concise
# Check highway alerts for specific region (RegionID: 9)
echo "=== Regional Alerts ==="
fetch-dottie fetchAlertsByRegionId '{"RegionID": 9}' --limit 5
# Check weather from specific station (StationID: 1909)
echo "=== Weather Station ==="
fetch-dottie fetchWeatherInformationByStationId '{"StationID": 1909}'
# Get ferry fares for tomorrow's trip
echo "=== Ferry Fares ==="
fetch-dottie fetchFareLineItemsByTripDateAndTerminals '{"TripDate": "2025-01-28", "DepartingTerminalID": 3, "ArrivingTerminalID": 7, "RoundTrip": false}' --pretty
# Fast testing without validation
echo "=== Quick Test ==="
fetch-dottie fetchVesselBasicsByVesselId '{"VesselID": 74}' --no-validation --silent
# Check bridge clearances for I-5
echo "=== Bridge Clearances ==="
fetch-dottie fetchBridgeClearancesByRoute '{"Route": "005"}' --concise๐ Example Projects
For Hobbyists
- Ferry Tracker - Real-time map showing vessel locations and wait times
- Traffic Camera Viewer - Browse and view traffic cameras by region
- Weather Dashboard - Road conditions and weather for your commute
- Toll Calculator - Plan trips with real-time toll pricing
For Developers
- Transportation Analytics - Analyze traffic patterns and ferry usage
- Route Planning - Integrate real-time data into navigation apps
- Emergency Response - Monitor highway alerts and conditions
- Logistics Tools - Commercial vehicle routing with restrictions
For Enterprise
- Fleet Management - Track vehicles with real-time traffic data
- Supply Chain Planning - Optimize routes using traffic and weather data
- Public Safety - Monitor transportation infrastructure
- Urban Planning - Analyze transportation patterns and trends
๐งช Testing
WS-Dottie includes comprehensive testing with support for both Node.js and browser environments.
# Quick test commands
npm run test:e2e # E2E tests (Node.js)
npm run test:module # Module-specific tests
npm run test:direct # Direct vitest execution
# Documentation generation
npm run docs:generate # Generate all documentation (OpenAPI + HTML)
npm run docs:openapi # Generate OpenAPI specifications only
npm run docs:html # Generate HTML documentation only
npm run docs:samples:fetch # Fetch fresh sample data for documentationE2E Testing: Tests all API endpoints with real data validation and error handling. Tests are organized per endpoint (one test file per endpoint, 97 files total), providing granular testing and easy filtering. Each test file uses the createEndpointSuite helper to automatically generate standard tests for the endpoint.
TanStack Query Testing: Comprehensive testing of React hooks with caching strategies, error states, and loading states.
JSONP Testing: Use --jsonp flag or JSONP=true environment variable to test browser environment compatibility.
๐ For detailed testing information, see Testing Architecture
๐๏ธ Governance
Maintained by Ferryjoy npm org. Issues and contributions welcome.
๐ค Contributing
We welcome contributions! Please see our development guide for setup instructions.
๐ License
MIT License - see LICENSE for details.
Made with โค๏ธ for Washington State travelers