3c6df95a86
Add TypeScript project references, update ESLint configs to support ESM modules, and introduce brand semantic color tokens across the web app. Add comprehensive documentation for architecture, API reference, development setup, and user guide.
150 lines
6.2 KiB
Markdown
150 lines
6.2 KiB
Markdown
# Core & API Client Reference
|
|
|
|
This document provides a detailed reference for the internal packages: `@timetoleave/core` and `@timetoleave/api-client`.
|
|
|
|
## 📦 `@timetoleave/core`
|
|
|
|
The core package contains all domain types, status calculation logic, HAFAS time parsing, and formatting utilities. It has zero runtime dependencies outside of the standard library.
|
|
|
|
### Types (`types.ts`)
|
|
|
|
| Interface | Description |
|
|
| :--- | :--- |
|
|
| `Event` | Represents a calendar event with an assigned destination and event time. |
|
|
| `CalendarEvent` | Raw calendar event data (typically `string` dates before conversion to `Event`). |
|
|
| `Station` | A transport station with a name, HAFAS `extId`, and optional coordinates. |
|
|
| `Journey` | A public transport connection including scheduled/real departure/arrival, delay, platform, and cancellation status. |
|
|
| `BikeRoute` / `WalkRoute` | Routing data including total distance, duration, and step-by-step instructions. |
|
|
| `CountdownInfo` | Output of the countdown utility containing a label, color code, and urgency flag. |
|
|
| `ReminderSettings` | User preferences for buffers, walking/bike options, and reminder toggles. |
|
|
| `WienerLinienDeparture` | Specific types for WienerLinien (Vienna public transport) monitor responses. |
|
|
|
|
### HAFAS Time Utilities (`hafas-time.ts`)
|
|
|
|
HAFAS timestamps are strictly tied to the `Europe/Vienna` timezone (CET/CEST). These utilities handle the bi-directional conversion between UTC JavaScript `Date` objects and HAFAS strings, correctly handling Daylight Saving Time (DST) transitions.
|
|
|
|
```typescript
|
|
import { parseHafasTime, hafasDateTime } from '@timetoleave/core';
|
|
|
|
// Parse HAFAS date ("YYYYMMDD") and time ("HHMMSS") into a UTC Date object
|
|
const dateObj = parseHafasTime("20231027", "143000");
|
|
|
|
// Convert a UTC Date object back to HAFAS date and time strings
|
|
const { date, time } = hafasDateTime(dateObj);
|
|
// Returns: { date: "20231027", time: "143000" }
|
|
```
|
|
|
|
> **Note:** `getTimezoneOffsetMinutes` is designed exclusively for full-hour offsets like `Europe/Vienna`. It will produce incorrect results for fractional timezones (e.g., India +05:30).
|
|
|
|
### Countdown & Status Utilities
|
|
|
|
#### `calculateCountdown(targetDate: Date): CountdownInfo`
|
|
Calculates the time delta between `now` and `targetDate`, returning a human-readable label, a color code, and an urgency boolean.
|
|
|
|
| Time Delta | Label | Color | Urgent |
|
|
| :--- | :--- | :--- | :--- |
|
|
| `<= 0 min` | `Now` | `red` | `true` |
|
|
| `<= 10 min` | `[X]min` | `orange` | `true` |
|
|
| `<= 30 min` | `[X]min` | `yellow` | `false` |
|
|
| `<= 60 min` | `[X]min` | `green` | `false` |
|
|
| `> 60 min` | `[X]h [Y]min` | `blue` | `false` |
|
|
|
|
#### `getLeaveStatus(event: Event, journeys: Journey[]): string`
|
|
Derives a human-readable leave-by status by finding the earliest non-cancelled journey and comparing its real departure time (`rD`) against the current time.
|
|
|
|
**Possible Returns:**
|
|
- `"No journey data"`
|
|
- `"All journeys cancelled"`
|
|
- `"Departure missed"` (if `rD` is in the past)
|
|
- `"Delayed +[X] min"` (if delay exceeds 10 minutes)
|
|
- `"Leave now"` (if departure is within 15 minutes)
|
|
- `"On time"`
|
|
|
|
### Formatting Utilities (`formatting.ts`)
|
|
|
|
All formatting functions default to the `de-AT` locale to match the primary target region.
|
|
|
|
- `formatTime(date: Date)` -> `"14:30"`
|
|
- `formatDate(date: Date)` -> `"Mi., 27. Oktober 2023"`
|
|
- `formatDateTime(date: Date)` -> `"27. Oktober 2023, 14:30"`
|
|
- `formatDuration(seconds: number)` -> `"1h 23min"` or `"45min"`
|
|
- `formatDistance(meters: number)` -> `"1.2km"` or `"800m"`
|
|
|
|
---
|
|
|
|
## 🌐 `@timetoleave/api-client`
|
|
|
|
The API client is a lightweight wrapper around the Web App's Next.js API routes. It handles URL construction, query parameters, and JSON serialization.
|
|
|
|
### Initialization
|
|
|
|
```typescript
|
|
import { ApiClient } from '@timetoleave/api-client';
|
|
|
|
// Initialize with the base URL of the backend proxy
|
|
const api = new ApiClient('http://localhost:3000');
|
|
```
|
|
|
|
### Methods
|
|
|
|
#### `getHealth()`
|
|
```typescript
|
|
getHealth(): Promise<{ status: 'ok'; uptime: number }>
|
|
```
|
|
Checks the `/api/health` endpoint to verify backend availability.
|
|
|
|
#### `geocode(name: string, countrycodes?: string)`
|
|
```typescript
|
|
geocode(name: string, countrycodes?: string): Promise<GeocodeResult[]>
|
|
```
|
|
Performs forward geocoding via `/api/geocode`.
|
|
|
|
#### `reverseGeocode(lat: number, lng: number)`
|
|
```typescript
|
|
reverseGeocode(lat: number, lng: number): Promise<GeocodeResult | null>
|
|
```
|
|
Performs reverse geocoding via `/api/geocode/reverse`.
|
|
|
|
#### `fetchCalendar(url: string, days?: number)`
|
|
```typescript
|
|
fetchCalendar(url: string, days?: number): Promise<CalendarEvent[]>
|
|
```
|
|
Fetches and parses a remote `.ics` file via `/api/calendar`. The optional `days` parameter limits the fetch to upcoming events.
|
|
|
|
#### `parseCalendarIcs(content: string)`
|
|
```typescript
|
|
parseCalendarIcs(content: string): Promise<CalendarEvent[]>
|
|
```
|
|
Parses raw `.ics` string content via `/api/calendar/parse`.
|
|
|
|
#### `searchStation(query: string)`
|
|
```typescript
|
|
searchStation(query: string): Promise<Station[]>
|
|
```
|
|
Searches for stations by name using the HAFAS `LocMatch` method. Returns up to 5 matches with valid `extId`s.
|
|
|
|
#### `searchJourneys(fromStationExtId: string, toStationExtId: string, date: Date)`
|
|
```typescript
|
|
searchJourneys(from: string, to: string, date: Date): Promise<Journey[]>
|
|
```
|
|
Sends a HAFAS `TripSearch` request to find public transport connections between two stations. It automatically converts the `Date` to HAFAS-compatible strings.
|
|
|
|
#### `getBikeRoute(fromLat, fromLng, toLat, toLng)` & `getWalkRoute(fromLat, fromLng, toLat, toLng)`
|
|
```typescript
|
|
getBikeRoute(...): Promise<BikeRoute>
|
|
getWalkRoute(...): Promise<WalkRoute>
|
|
```
|
|
Retrieves routing data for the "first mile / last mile" segment (e.g., biking from home to the train station).
|
|
|
|
#### `findNearbyStops(lat: number, lng: number, radius?: number)`
|
|
```typescript
|
|
findNearbyStops(lat: number, lng: number, radius: number = 1000): Promise<NearbyStop[]>
|
|
```
|
|
Finds public transport stops within a specific radius using the WienerLinien API (`/api/wienerlinien/stops`).
|
|
|
|
#### `hafasRequest<T>(body: unknown)`
|
|
```typescript
|
|
hafasRequest<T>(body: unknown): Promise<T>
|
|
```
|
|
A generic method to send arbitrary HAFAS protocol bodies to `/api/hafas`. Useful for advanced use-cases not covered by the wrapper methods.
|